Reputation: 943
I working with Angular 8.
This question is only for Angular DI experts.
At first, I made an Angular library that will be reused in many project.
In this Library, I made an abstract service, that have to be defined in the project using it.
I defined an abstract class in my Library named BridgeService
and In my main project, I create my BridgeService implementing it: ( in the next lines, I will show you the abstract BridgeService)
MainProject > BridgeService :
import { BridgeService as AbstractBridgeService } from 'myLibrary';
@Injectable()
export class BridgeService implements AbstractBridgeService {
hello(){
alert('hello Word');
}
}
MainProject > UsersModule :
import { UsersModule as LibraryUsersModule } from 'myLibrary';
@NgModule({
imports: [
CommonModule,
LibraryUsersModule,
],
//...
providers: [
BridgeService
// some try:
//{ provide: BridgeService, useClass: BridgeService }
],
})
export class UsersModule {
constructor(private bridgeService: BridgeService){
this.bridgeService.hello();
}
}
And now we have to see the library concerned files:
Library > bridge.service.ts:
export abstract class BridgeService {
abstract hello(): void;
}
This BridgeService have to be defined in UsersModule
Library > UsersModule:
@NgModule({
//...
providers: [
// My Try:
{ provide: BridgeService, useValue: BridgeService}
],
})
export class UsersModule {
# my goal is that I can uncomment this piece of code:
//constructor(private bridgeService: BridgeService){
// this.bridgeService.hello();
//}
}
I want that you touch just two lines in this code:
1) In library's UsersModule providers array: the line of BridgeService that I want to declare as an abstract to be generic.
2) In project's UsersModule providers array: the line of BridgeService that I want to define to take place of the abstract in the Library UserModule.
Upvotes: 9
Views: 2623
Reputation: 9377
You need to define a token in your library, that's all. In your library, you define the token and the interface:
/** Token to inject the bridge service */
export const BRIDGE_SERVICE_ADAPTER:
InjectionToken<BridgeServiceAdapter> =
new InjectionToken<BridgeServiceAdapter>('Bridge service token');
export interface BridgeServiceAdapter {
hello(): void;
}
Inside your library, you can inject it like this:
export class UsersModule {
constructor(
@Inject(BRIDGE_SERVICE_ADAPTER) private bridgeService: BridgeServiceAdapter
){
if(!bridgeService) {
throw new Error('You must provide a bridge adapter');
}
this.bridgeService.hello();
}
}
And, in the app where you're going to use the library:
import { BridgeServiceAdapter } from 'myLibrary';
@Injectable({providedIn: 'root'})
export class BridgeService implements BridgeServiceAdapter {
hello() { alert('hello Word') }
}
...
import { UsersModule as LibraryUsersModule, BRIDGE_SERVICE_ADAPTER } from 'myLibrary';
@NgModule({
imports: [CommonModule,LibraryUsersModule,...],
providers: [{ provide: BRIDGE_SERVICE_ADAPTER, useExisting: BridgeService }],
})
export class UsersModule {
// Obs 1: ok, this seems something you should be encapsulating inside
// your library to doesn't have to inject in the dependent projects
// Obs 2: and, here, in the app, as I created BridgeService decorated
// with {providedIn: 'root'}, I can inject the service itself. But
// if this wasn't the case, I'd have to inject it using the same notation
// used in the library:
// @Inject(BRIDGE_SERVICE_ADAPTER) private bridgeService: BridgeServiceAdapter
// This would be necessary if I had decorated my service with
//
// @Injectable() (instead of @Injectable({providedIn: 'root'}))
//
// and provided it globally like this:
//
// { provide: BRIDGE_SERVICE_ADAPTER, useClass: BridgeService }
//
// On the above line, notice "useClass" instead of "useExisting"
constructor(private bridgeService: BridgeService) {
this.bridgeService.hello();
}
}
Upvotes: 14