Angular2 factory provider pattern

This is just a note of the provider pattern for services in Anglar2 which has been somewhat elusive to me, moving from Angular1 to Anguar2 and TypeScript. Trolling the internet I’ve found that the following works:

Creating a “logger service” by ng generate service service/logger creates a service scaffold in service/logger.service.ts.

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

@Injectable()
export class LoggerService {

	constructor() {
	console.log('LoggerService constructor');
	}

}

A provider is the just a “plain old Javascript object” constituting a providr entry of a @NgModule which we export from service/logger.service.provider.ts.

import { LoggerService } from './logger.service';

let loggerServiceFactory = () => {
	console.log('loggerServiceFactory()');
	return new LoggerService();
};

export let loggerServiceProvider =
	{ provide: LoggerService,
	  useFactory: loggerServiceFactory,
	  deps: []
	};

Finally, we declare the provider in a @NgModule in the provider clause.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';
import { DemoComponentComponent } from './demo-component/demo-component.component';
import { LoggerService } from './service/logger.service';
import { loggerServiceProvider } from './service/logger.service.provider';
import { NavComponent } from './nav/nav.component';


@NgModule({
  declarations: [
	AppComponent,
	DemoComponentComponent,
	NavComponent
  ],
  imports: [
	BrowserModule,
	AppRoutingModule
  ],
  providers: [loggerServiceProvider],
  bootstrap: [AppComponent]
})
export class AppModule { }

This lets me inject LoggerServices into components throughout the app in the familliar manner

import { Component, OnInit } from '@angular/core';
import { LoggerService } from '../service/logger.service';

@Component({
	selector: 'app-demo-component',
	templateUrl: './demo-component.component.html',
	styleUrls: ['./demo-component.component.scss']
})
export class DemoComponentComponent implements OnInit {

	log: LoggerService;

	constructor(log: LoggerService) {
	this.log = log;
	}

	ngOnInit() { }

}

In the Javascript console of a browser I can see that the creation of the LoggerService invokes my loggerServiceProvider.

I then changed the logger.service.provider.ts into

import { LoggerService } from './logger.service';

let name: string = "None";

let loggerServiceFactory = () => {
	console.log('loggerServiceFactory()');
	return new LoggerService(this.name);
};

export let loggerServiceProvider = (name: String) => {
	this.name = name;    
	return { provide: LoggerService,
		 useFactory: loggerServiceFactory,
		 deps: []
	   };
};

which aloows for a parameterized service, the loggerServiceProvider becomes what one in the olden days would call $get. This can be used in the app.module.ts to initiate services.

 import { BrowserModule } from '@angular/platform-browser';
 import { NgModule } from '@angular/core';

 import { AppRoutingModule } from './app-routing.module';

 import { AppComponent } from './app.component';
 import { DemoComponentComponent } from './demo-component/demo-component.component';
 import { LoggerService } from './service/logger.service';
 import { loggerServiceProvider } from './service/logger.service.provider';
 import { NavComponent } from './nav/nav.component';


 @NgModule({
   declarations: [
	 AppComponent,
	 DemoComponentComponent,
	 NavComponent
   ],
   imports: [
	 BrowserModule,
	 AppRoutingModule
   ],
	 providers: [
	   loggerServiceProvider('Mats')
	 ],
   bootstrap: [AppComponent]
 })
 export class AppModule {}

The clause

providers: [loggerServiceProvider('Mats')]` 

should be more something like

providers: [rootResource('/api')]

in a serious application.

The two examples shows the patterns formerly known as the .provider() pattern and the .factory() pattern respectively.

Nifty.

Leave a comment