Last active
October 2, 2020 13:22
-
-
Save ghetolay/6d4dc2c6d26c9b850c1e6be686866c7f to your computer and use it in GitHub Desktop.
Create singleton provider for Angular
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This function allows you to create singleton service that'll stay singleton throughout all the app. | |
Even(especially) if you use lazy module. | |
This covers that problem : https://angular.io/docs/ts/latest/guide/ngmodule.html#!#why-_userservice_-isn-t-shared | |
Idea isn't mine, it's how they handle it on Angular Material. I'm just creating an helper function for it. | |
Basically we create a factory provider instead of a plain class provider and inject the service into the factory function. | |
If the service is present it means it has already been instantiated somewhere in the injector tree and we can return it. | |
If injection fails and service is nulll this means we are the first provider so we can instantiate and return the service. | |
*/ | |
export function createSingletonProvider<T extends Type<any>, R>( | |
service: T, | |
token?: T | InjectionToken<R>,// `token = service` breaks aot so we use `token || service` instead below | |
// dependencies must be in same order as the service's constructor signature. | |
dependencies: any[] = [], | |
// fake argument here just a trick to create a var | |
ctorToken = new InjectionToken('service ctor') | |
): Provider[] { | |
return [ | |
{ | |
provide: ctorToken, | |
useValue: service | |
}, { | |
provide: token || service, | |
deps: [ctorToken, [new Optional(), new SkipSelf(), token || service], ...dependencies], | |
useFactory: createSingletonFactory | |
} | |
]; | |
} | |
export function createSingletonFactory(serviceCtor: Function, parentService?: Type<any>, ...dependencies: any[]) { | |
if (parentService !== null) { | |
return parentService; | |
} | |
const instance = Object.create(serviceCtor.prototype); | |
instance.constructor.apply(instance, dependencies); | |
return instance; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Injectable() | |
export class Service { | |
} | |
@Injectable() | |
export class ServiceWithDeps { | |
constructor(dep1: Dep1, dep2: Dep2){ } | |
} | |
/* use */ | |
@NgModule({ | |
createSingletonProvider(Service, Service), | |
// /!\ Dependencies order must be the same as the constructor signature | |
createSingletonProvider(ServiceWithDeps, ServiceWithDeps, [Dep1, Dep2]) | |
}) | |
/* instead of */ | |
@NgModule({ | |
providers: [ | |
Service, | |
ServiceWithDeps | |
] | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment