Книга: Angular 2 Cookbook
Назад: Injecting a value as a service with useValue and OpaqueTokens
Дальше: 8. Application Organization and Management

Building a provider-configured service with useFactory

One further extension of dependency injection in Angular 2 is the ability to use factories when defining your provider hierarchy. A provider factory allows you to accept input, perform arbitrary operations to configure the provider, and return that provider instance for injection.

Note

The code, links, and a live example of this are available at .

Getting ready

Begin again with the dual service and article component setup shown in Service injection aliasing with useClass and useExisting, earlier in the chapter.

How to do it...

Provider factories in Angular 2 are exactly as you might imagine they would be: functions that return a provider. The factory can be specified in a separate file and referenced with the useFactory provide option.

Begin by combining the two services into a single service, which will be configured with a method call:

[app/article.service.ts]      import {Injectable} from '@angular/core';      @Injectable()   export class ArticleService {     private title_:string =        "Flying Spaghetti Monster Sighted";     private body_:string =        "Adherents insist we are missing the point";     private notes_:string = "Spot on!";     private editorEnabled_:boolean = false;        getArticle():Object {       var article = {         title: this.title_,         body: this.body_       };       if (this.editorEnabled_) {         Object.assign(article, article, {           notes: this.notes_         });       }       return article;     }        enableEditor():void {       this.editorEnabled_ = true;     }   }   

Defining the factory

Your objective is to configure this service to have enableEditor() invoked based on a boolean flag. With provider factories, this is possible. Define the factory in its own file:

[app/article.factory.ts]      import {ArticleService} from './article.service';      export function articleFactory(enableEditor?:boolean):ArticleService {     return (articleService:ArticleService) => {       if (enableEditor) {         articleService.enableEditor();       }       return articleService;     }   }   

Injecting OpaqueToken

Splendid! Next, you'll need to reconfigure ArticleComponent to inject a token rather than the desired service:

[app/article.token.ts]      import {OpaqueToken} from '@angular/core';      export const ArticleToken = new OpaqueToken('app.article');   [app/article.component.ts]      import {Component, Inject} from '@angular/core';   import {ArticleToken} from './article.token';      @Component({     selector: 'article',     template: `       <h2>{{article.title}}</h2>       <p>{{article.body}}</p>       <p *ngIf="article.notes">         <i>Notes: {{article.notes}}</i>       </p>     `   })   export class ArticleComponent {     article:Object;          constructor(@Inject(ArticleToken) private articleService_) {        this.article = articleService_.getArticle();     }   }   

Creating provider directives with useFactory

Finally, you'll need to define the directives that specify how to use this factory and incorporate them into the application:

[app/default-view.directive.ts]      import {Directive} from '@angular/core';   import {ArticleService} from './article.service';   import {articleFactory} from './article.factory';   import {ArticleToken} from './article.token';      @Directive({     selector: '[default-view]',     providers: [           {provide: ArticleToken,          useFactory: articleFactory(),         deps: [ArticleService]       }     ]   })   export class DefaultViewDirective {}   [app/editor-view.directive.ts]      import {Directive} from '@angular/core';   import {ArticleService} from './article.service';   import {articleFactory} from './article.factory';   import {ArticleToken} from './article.token';      @Directive({     selector: '[editor-view]',     providers: [           {         provide: ArticleToken,         useFactory: articleFactory(true),         deps: [ArticleService]       }     ]   })   export class EditorViewDirective {}   [app/root.component.ts]      import {Component} from '@angular/core';      @Component({     selector: 'root',     template: `       <article default-view></article>       <article editor-view></article>     `   })   export class RootComponent {}   

With this, you should be able to see both the versions of ArticleComponent.

How it works...

The article component is redefined to use a token instead of a service injection. With the token, Angular will walk up the component tree to find where that token is provided. The directives declare that the token is mapped to a provider factory, which is a method invoked to return the actual provider.

useFactory is the property that maps to the factory function. deps is the property that maps to the service dependencies that the factory has.

There's more...

An important distinction at this point is to recognize that all these factory configurations are happening before any components are instantiated. The class decoration that defines the providers will invoke the factory function on setup.

See also

  • Controlling service instance creation and injection with NgModule gives a broad overview of how Angular 2 architects provider hierarchies using modules
  • Service injection aliasing with useClass and useExisting demonstrates how to intercept dependency injection provider requests
  • Injecting a value as a service with useValue and OpaqueTokens show how you can use dependency injected tokens to inject generic objects
Назад: Injecting a value as a service with useValue and OpaqueTokens
Дальше: 8. Application Organization and Management

thank you
Flame
cant read the code since it is all on a single line. Also this comments section is russian
Rakuneque
DATA COLLECTION AND ANALYSIS Two reviewers extracted data and assessed methodological quality independently lasix torsemide conversion Many others were in that space already