Angular 4 Services (Http) Inheritance
Inheriting in Angular 4, meaning Typescript combined with Dependency Injection, can be tougher than you would expect.
lets say we just want a base class for all of our Services, they all use a WebApi, so they have their base url, which always bring the "all" array, and then "\3" for each item. so they all look like this:
so you would like to make this the base class and each service just declaring its own "All Items" array and url. so you would thing this would work:
HELL NO!
1st error:
ok, so lets move private http:Http outside the CTOR, ok, we got it how is should be done with TypeScript, the project builds.
but now you should start getting Angular errors such as, 1st of all
"ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'get' of undefined
TypeError: Cannot read property 'get' of undefined"
that simply means, and you should see your line of code using "http.get", that "http" is undefined.
so how do we create a new instance of http? and why with the DI (Dependency Injection) it worked?
well DI works in a way that whatever you throw into your CTOR it will resolve it by itself, but if you need it somewhere else you sometimes need to work hard, like with Http.
so if you try to make new Http(), as optional parameter or private, you'll end up doing this:
private http:Http = new Http(
that is your 1st option.
2nd is to use the Injector ReflectiveInjector like this (same imports)
will give the same results.
NOTICE with RC6 you must use useFactory: () => new CookieXSRFStrategy and now useClass, and anyway, the point is that you must work hard a little for a private, base Http.
-------------------------------------
Yet another option, that sometimes is the better one, is to create a Manager Class, such as this:
if you dont use @Inject nor @Injectable you should get
Uncaught Error: Can't resolve all parameters for RequestManager: (?).
and then use in in your service CTOR like this:
but then you'll see yet another error:
ERROR Error: No provider for RequestManager!
this is because you need to register it as a provider. you can register a provider to an @NgModule or @Component . so for the services you should use your AppModule .
Enjoy!
lets say we just want a base class for all of our Services, they all use a WebApi, so they have their base url, which always bring the "all" array, and then "\3" for each item. so they all look like this:
export class ServiceBaseClass {
constructor(private baseUrl, private http:Http) {}
//public functions using baseUrl and http like
Get(itemID = ""){
var url = this.baseUrl + itemID;
var promise = new Promise ((resolve, reject) => {
this.http.get(url); // and whatever
})
}
}
so you would like to make this the base class and each service just declaring its own "All Items" array and url. so you would thing this would work:
export class ChocolateService extends ServiceBaseClass {
constructor() {
super('http://chocolate/');
this.Get();
}
}
HELL NO!
1st error:
ok, so lets move private http:Http outside the CTOR, ok, we got it how is should be done with TypeScript, the project builds.
but now you should start getting Angular errors such as, 1st of all
"ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'get' of undefined
TypeError: Cannot read property 'get' of undefined"
that simply means, and you should see your line of code using "http.get", that "http" is undefined.
so how do we create a new instance of http? and why with the DI (Dependency Injection) it worked?
well DI works in a way that whatever you throw into your CTOR it will resolve it by itself, but if you need it somewhere else you sometimes need to work hard, like with Http.
so if you try to make new Http(), as optional parameter or private, you'll end up doing this:
import { Http, Response, Headers, RequestOptions, ResponseOptions } from '@angular/http';
import { XHRBackend, ConnectionBackend, BrowserXhr, XSRFStrategy, BaseResponseOptions, CookieXSRFStrategy, BaseRequestOptions } from '@angular/http';
private http:Http = new Http(
new XHRBackend(
new BrowserXhr(), new ResponseOptions(), new CookieXSRFStrategy()),
new RequestOptions()
);
that is your 1st option.
2nd is to use the Injector ReflectiveInjector like this (same imports)
private http:Http;
constructor(private baseUrl) {
this.http = ReflectiveInjector.resolveAndCreate([
Http, BrowserXhr,
{ provide: ConnectionBackend, useClass: XHRBackend },
{ provide: ResponseOptions, useClass: BaseResponseOptions },
{ provide: XSRFStrategy, useFactory: () => new CookieXSRFStrategy },
{ provide: RequestOptions, useClass: BaseRequestOptions }
]).get(Http);
}
will give the same results.
NOTICE with RC6 you must use useFactory: () => new CookieXSRFStrategy and now useClass, and anyway, the point is that you must work hard a little for a private, base Http.
-------------------------------------
Yet another option, that sometimes is the better one, is to create a Manager Class, such as this:
export class RequestManager {
public baseUrl;
constructor(@Inject(Http) private http:Http) { }
if you dont use @Inject nor @Injectable you should get
Uncaught Error: Can't resolve all parameters for RequestManager: (?).
and then use in in your service CTOR like this:
constructor(public requestManager:RequestManager) {
requestManager.baseUrl ='http://chocolate/';
but then you'll see yet another error:
ERROR Error: No provider for RequestManager!
this is because you need to register it as a provider. you can register a provider to an @NgModule or @Component . so for the services you should use your AppModule .
providers: [ RequestManager ],
Enjoy!
Save your time and get the best software built by the experts by simply a hiring Angular development company in USA.
ReplyDelete