Reputation: 133
I have a Master-Detail component that contains children grid and detail components.
Based on an @Input entityType parameter, the grid and the detail components will need to initialize their specific dataService property to DataService1, DataService2, ... or DataServiceN. What would be the best way to achieve this ? I see various possibilities:
Create an @Injectable
factory service with a createServiceInstance(entityType)
method:
public createService(type: EntityType): any {
switch (type) {
case EntityType.Type1:
return new DataService1();
case EntityType.Type2:
return new DataService2();
case EntityType.TypeN:
return new DataServiceN();
}
}
Then inject that service into Master-Detail Component constructor and assign do
this.dataService = this.factoryService.createService(entityType)
in ngOnInit / ngOnChanges. We then add @Input dataService to grid and detail components and bind it to masterDetail dataService property.
Use an Injector service in detail/grid components, have the providers property of @Component decorator set to [DataService1, DataService2, ..., DataServiceN] and then in ngOnInit do
this.dataService = this.injector.get(getDataService(entityType))
with
export function getDataService(entityType: string): any {
switch (type) {
case EntityType.Type1:
return DataService1;
case EntityType.Type2:
return DataService2;
case EntityType.TypeN:
return DataServiceN;
}
}
Use a mix of 1) and 2) : provide ServiceFactory with [DataService1, DataService2, ..., DataServiceN] in its constructor, then in detail/grid component ngOnInit do
this.dataService = this.factoryService.getDataService(entityType)
with
getDataService(entityType: string): any {
switch (type) {
case EntityType.Type1:
return this.dataService1;
case EntityType.Type2:
return this.dataService2;
case EntityType.TypeN:
return this.dataServiceN;
}
}
Another solution?
I'm using Angular 4 with TypeScript.
Upvotes: 2
Views: 997
Reputation: 564
I had a similar issue and found following working solution:
I have interface FileService:
export interface FileService {
downloadDocument(ownerId: string, fileId: string): Observable<any>;
}
Then I have all the possible services implement this interface. In the child component I have an input:
export class SomeTestComponentComponent {
@Input() fileService: FileService;
download() {
console.log(this.fileService);
// this.fileService.download(...);
}
}
Now in the parent component I can decide which service should be used in this instance of the component:
<app-some-test-component [fileService]="fileServiceImpl" ></app-some-test-component>
This approach means you don't supply a string to decide which service to use but rather the service itself.
Upvotes: 0