Apr 6, 2017

Angular2 Service Dependency Injection

A provider provides the concrete, runtime version of a dependency value.
{ provide: Logger, useClass: Logger} is same as Logger. This tells the injector to return instance of Logger when someone ask for Logger
{ provide: Logger, useClass: BetterLogger} - This tells the injector to return instance of BetterLogger when someone ask for Logger
Now you can inject logger by using a Logger type which is dependency injection token. In the following example an instance of Logger (or BetterLogger) will be injected via private property logger. Within the class you should get proper intellisense and type safety based on type Logger
constructor(private logger: Logger){}

Its better to always use decorator @Injectable() to a service class, even though its only mandatory if your service has dependency (inject other service as dependency of its own) on some other service. Decorators simply add meta to our code when transpiled.

MyService = __decorate([
        Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Injectable"])(),
        __metadata("design:paramtypes", [_angular_common_http__WEBPACK_IMPORTED_MODULE_2__["HttpClient"]])
    ], MyService );
Here The paramtypes metadata is the one that is needed by Angular’s DI to figure out, for what type it has to return an instance.
TypeScript generates metadata when the emitDecoratorMetadata option is set and decorator is attached to the class, method etc

OpaqueToken
These are used to create non class dependency. For example for jQuery or any other third party library which do not have typescript class you can define OpaqueToken

import {OpaqueToken} from "@angular/core";
export let JQ_TOKEN = new OpaqueToken("my app jquery");

Similarly for DI on interface you can define OpaqueToken
export interface AppConfig {
 apiEndpoint: string;
 title: string;
}

export const HERO_DI_CONFIG: AppConfig = {
 apiEndpoint: 'api.heroes.com',
 title: 'Dependency Injection'
};

import { OpaqueToken } from '@angular/core';

export let APP_CONFIG = new OpaqueToken('my app config');

Now in the providers you can use it like this


{ provide: JQ_TOKEN, useValue: myAppjQuery }


Here you need to have myAppjQuery defined (let myAppjQuery: Object = window["$"];). Where ever you use JQ_TOKEN you will get handle of myAppjQuery, which at runtime will initialize as window["$"], so as long as jQuery is loaded in the rootwindow, you should be able to user it.
{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }

The above example is for interface which is not typescript class, so we defined Opaque token for that. Where ever this token will be used it will refer to value HERO_DI_CONFIG.

Now in your application, you should be able to inject this like this
constructor(@Inject(JQ_TOKEN) private $: any){}
constructor(@Inject(APP_CONFIG) config: AppConfig) {}

No comments:

Post a Comment