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 LoggerService
s 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.