Skip to content

Instantly share code, notes, and snippets.

@bennadel
Created October 28, 2016 12:37
Handling Service Configuration Without A Configuration Phase In Angular 2.1.1
// Import the application components and services.
import { IGreetTransformer } from "./greeter/greeter.module";
// I add a compliment to the end of the greeting.
export class ComplimentTransformer implements IGreetTransformer {
// I transform the given value as part of the Greeter reduction.
public transform( value: string ) : string {
return( value + " You look beautiful this morning." );
}
}
// I convert the greeting to UPPERCASE!!! FOR THE WIN!!!
export class YellingTransformer implements IGreetTransformer {
// I transform the given value as part of the Greeter reduction.
public transform( value: string ) : string {
return( value.toUpperCase().replace( /\./g, "!" ) );
}
}
// Import the core angular services.
import { Component } from "@angular/core";
// Import the application components and services.
import { Greeter } from "./greeter/greeter.module";
@Component({
selector: "my-app",
template:
`
<em>Look in the console to see the Greeter result.</em>
`
})
export class AppComponent {
// I initialize the component.
constructor( greeter: Greeter ) {
console.group( "Testing Greeter" );
console.log( greeter.greet( "Sarah" ) );
console.groupEnd();
}
}
// Import the core angular services.
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
// Import the application components and services.
import { AppComponent } from "./app.component";
import { ComplimentTransformer } from "./app-transformers";
import { GreeterModule } from "./greeter/greeter.module";
import { GREETER_TRANSFORMERS } from "./greeter/greeter.module";
import { YellingTransformer } from "./app-transformers";
// NOTE: This import is here for use with the Factory (which is commented-out).
import { Greeter } from "./greeter/greeter.module";
@NgModule({
bootstrap: [ AppComponent ],
imports: [ BrowserModule, GreeterModule ],
providers: [
// As part of the Greeter "configuration", we can setup a collection of
// Transformers to be injected into the Greeter as part of the instantiation
// process. In this way, we are replacing the Angular 1 "configuration phase"
// with dependency-injection mechanics.
{
provide: GREETER_TRANSFORMERS,
multi: true, // <-- This creates an array for a single injectable.
useClass: ComplimentTransformer
},
{
provide: GREETER_TRANSFORMERS,
multi: true, // <-- This creates an array for a single injectable.
useClass: YellingTransformer
}
// We could have also used a Factory function to accomplish a similar outcome,
// letting the dependency-injection system instantiate the individual
// transformers and then allowing us to manually instantiate the Greeter with
// the given collection.
/*
ComplimentTransformer,
YellingTransformer,
{
provide: Greeter,
deps: [ YellingTransformer, ComplimentTransformer ],
useFactory: function(
yellingTransformer: YellingTransformer,
complimentTransformer: ComplimentTransformer
) : Greeter {
// When using a Factory, we have to manually assemble the collection of
// transformers that we want to inject into the Greeter.
return( new Greeter( [ complimentTransformer, yellingTransformer ] ) );
}
}
*/
],
declarations: [ AppComponent ]
})
export class AppModule {
// ... nothing to do here.
}
// Import the core angular services.
import { NgModule } from "@angular/core";
// Import the application components and services.
import { CoreGreetTransformer } from "./transformers";
import { Greeter } from "./greeter";
import { GREETER_TRANSFORMERS } from "./greeter";
// "Barrel" exports.
// --
// NOTE: Traditionally, this kind of exporting of the "public" values from a module is
// done in a "barrel" file (ie, index.ts). However, in order to keep this demo smaller,
// I'm co-opting the Module file to play double-duty as both the module and the "barrel".
export { Greeter } from "./greeter";
export { GREETER_TRANSFORMERS } from "./greeter";
export { IGreetTransformer } from "./transformers";
@NgModule({
providers: [
Greeter,
// When Angular instantiates the Greeter class, it's going to inject this
// collection of Transformers. By default, the Greeter module is configured to
// supply the one "core" Transformer. However, the application at large can
// easily add to this "multi" dependency collection.
{
provide: GREETER_TRANSFORMERS,
multi: true,
useClass: CoreGreetTransformer
}
]
})
export class GreeterModule {
// ... nothing to do here.
}
// Import the core angular services.
import { Inject } from "@angular/core";
import { OpaqueToken } from "@angular/core";
// Import the application components and services.
import { IGreetTransformer } from "./transformers";
// I am the dependency-injection token that can be used to aggregate greet transformers.
// This is the collection that will be injected into the Greeter class during application
// bootstrapping. This kind of "multi" collection replaces the concept of a configuration
// phase in Angular 1.
export var GREETER_TRANSFORMERS = new OpaqueToken( "Injection token for Greet transformers." );
// I provide a service for generating greeting messages.
export class Greeter {
private transformers: IGreetTransformer[];
// I initialize the service.
constructor( @Inject( GREETER_TRANSFORMERS ) transformers: IGreetTransformer[] ) {
this.transformers = transformers;
}
// ---
// PUBLIC METHODS.
// ---
// I return the greeting for the given name.
public greet( name: string ) : string {
var greeting = this.transformers.reduce(
( reduction: string, transformer: IGreetTransformer ) : string => {
return( transformer.transform( reduction ) );
},
name
);
return( greeting );
}
}
// I am the interface that must be implemented by all greet transformers.
export interface IGreetTransformer {
transform( value: string ) : string;
}
// I am the core transformer that is used, no matter what collection of transformers have
// been configured for dependency-injection.
export class CoreGreetTransformer implements IGreetTransformer {
// I transform the given value as part of the Greeter reduction.
public transform( name: string ) : string {
return( "Hello " + name + "." );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment