0

I am trying to use the Angular 2 Router Lazy Loading to reduce initial load time.

In my app I have customized the original Http service of the Angular to display a loader whenever any http request is initiated which I hide on completion.

Currently, I have a GlobalService (which is a application wide singleton) which hold the current status of the Loading bar and HttpLoading class which extends Angular original Http class.

In AppModule I have added both to the providers so that these are available application wide:

export function httpFactory(backend: XHRBackend, defaultOptions: RequestOptions, globalService: GlobalService) {
        return new HttpLoading(backend, defaultOptions, globalService);
    }

and

providers: [
            GlobalService,
            {
                provide: Http,
                useFactory: httpFactory,
                deps: [XHRBackend, RequestOptions, GlobalService]
            }
        ],

I have the below AppModule:

//angular
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Http, XHRBackend, HttpModule, RequestOptions, JsonpModule } from '@angular/http';
import { NgModule } from '@angular/core';

//material
import { MdProgressBarModule } from '@angular2-material/progress-bar';

import { HomeModule } from './home/home.module';

import { AppComponent } from './app.component';

//services
import { GlobalService } from './shared/services/global.service';
import { HttpLoading } from './shared/services/http-loading';

//routing
import { routing } from './app.routing';

export function httpFactory(backend: XHRBackend, defaultOptions: RequestOptions, globalService: GlobalService) {
    return new HttpLoading(backend, defaultOptions, globalService);
}

@NgModule({
    imports: [
        //angular
        BrowserModule,
        FormsModule,
        HttpModule,
        JsonpModule,
        ReactiveFormsModule,
        routing,

        //material
        MdProgressBarModule.forRoot(),
        HomeModule,
    ],
    declarations: [
        AppComponent,
    ],
    providers: [
        GlobalService,
        {
            provide: Http,
            useFactory: httpFactory,
            deps: [XHRBackend, RequestOptions, GlobalService]
        }
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

Below is my HttpLoading Class:

import { Http, ConnectionBackend, RequestOptions, RequestOptionsArgs, Response, Headers } from '@angular/http';
import { Injectable } from '@angular/core';
import { GlobalService } from './global.service';

import { Observable } from 'rxjs/Observable';
import "rxjs/add/operator/catch";

export class HttpLoading extends Http {

constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private _gs: GlobalService) {
        super(backend, defaultOptions);
    }

get(url: string, options?: RequestOptionsArgs): Observable<any> {
        this._gs.isLoading = true;

        return super.get(url, options)
            .map(res => {
                this._gs.isLoading = false;
                return res.json();
            });
    }

}

Below is my GlobalService

import { Injectable, Inject } from '@angular/core';

@Injectable() export class GlobalService { public isLoading: boolean = false; }

I tried to create below SharedModule which I thought I would inject in the AppModule and it will solve the problem:

import { NgModule, ModuleWithProviders } from "@angular/core";
import { Http, XHRBackend, HttpModule, RequestOptions, JsonpModule } from '@angular/http';
import { GlobalService } from './shared/services/global.service';
import { HttpLoading } from './shared/services/http-loading';

export function httpFactory(backend: XHRBackend, defaultOptions: RequestOptions, globalService: GlobalService) {
    return new HttpLoading(backend, defaultOptions, globalService);
}

@NgModule({
    imports: [
        //angular
        HttpModule,
        JsonpModule
    ]
})
export class SharedModule {
    static forRoot(): ModuleWithProviders {
        return {
            ngModule: SharedModule,
            providers: [GlobalService,
                {
                    provide: Http,
                    useFactory: httpFactory,
                    deps: [XHRBackend, RequestOptions, GlobalService]
                }]
        };
    }
}

And updated my AppModule to the below:

//angular
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Http, XHRBackend, HttpModule, RequestOptions, JsonpModule } from '@angular/http';
import { NgModule } from '@angular/core';

//material
import { MdProgressBarModule } from '@angular2-material/progress-bar';

import { HomeModule } from './home/home.module';
import { SharedModule } from './../shared.module';

import { AppComponent } from './app.component';


//routing
import { routing } from './app.routing';


@NgModule({
    imports: [
        //angular
        BrowserModule,
        FormsModule,
        HttpModule,
        JsonpModule,
        ReactiveFormsModule,
        routing,

        //material
        MdProgressBarModule.forRoot(),
        HomeModule,
        SharedModule
    ],
    declarations: [
        AppComponent,
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

But it didn't work. Whenever I visit any route which has http call, it throws error on console.

For example, in HomeCompnent in ngOnInit I make an http call to fetch some data. But when I move to this component, I displays below error in console.

EXCEPTION: _super.prototype.get.call(...).map is not a function


core.umd.js:3468 TypeError: _super.prototype.get.call(...).map is not a function
    at HttpLoading.get (http-loading.js:50)
    at HomeComponent.ngOnInit

Can anyone please guide what am I doing wrong?

1 Answer 1

1

Method 1:

In HttpLoading class file, add

import 'rxjs/add/operator/map';

Method 2(for systemjs):

You don't need method 1 if you do this.

In main.ts

import 'rxjs';

In systemjs.config.js;

map: {
  'rxjs': 'node_modules/rxjs',
},
packages: {
  'rxjs': { main: 'bundles/Rx.min.js', defaultExtension: 'js' },
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you John, it actually solved the map error but the service doesn't seem to be a singleton.
@NaveedAhmed Why GlobalService is depending on itself??
As per my understanding, since we have imported SharedModule in AppModule there shouldn't be any need to add it to the providers of the AppModule, rite? but if I dont add it it throws error of no provider for GlobalService.
And if I add it to providers list, then the service seems to act as singleton.
@NaveedAhmed Is it possible to put it in a github repo?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.