export interface InfoPanelComponent {
data: any;
}
export class ComplaintsComponent implements OnInit, InfoPanelComponent {
data: any;
constructor(private navigationService: NavigationService, private activatedRoute: ActivatedRoute) {
}
onCancelClicked() {
console.log(this.navigationService);
this.navigationService.hidePanel(this.data.key, this.activatedRoute);
}
}
The problem is, that this.navigationService
is undefined. The service itself is provided in the app.modules.ts
and can be injected in other components successfully.
I suppose the reason that it doesn't work is that the component above (and more components in future) is created dynamically:
private addPanel(item: InfoPanelItem, itemKey: string): void {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(item.component);
const viewContainerRef = this.infopanelHost.viewContainerRef;
// create new component
const componentRef = viewContainerRef.createComponent(componentFactory);
(<InfoPanelComponent>componentRef.instance).data = item.data;
}
I suppose that the services are not being injected because of that. Is there a way to generically inject all dependancies that the component requires? Note that the ComplaintsComponent
is just one example and there are more to come, that may require different services.
Angular provides the ability for you to inject a service into a component to give that component access to the service. The @Injectable() decorator defines a class as a service in Angular and allows Angular to inject it into a component as a dependency.
Factory providers: useFactory link The useFactory provider key lets you create a dependency object by calling a factory function, as in the following example. The injector provides the dependency value by invoking a factory function, that you provide as the value of the useFactory key.
What dynamic components are. Dynamic means, that the components location in the application is not defined at buildtime. That means, that it is not used in any angular template. Instead, the component is instantiated and placed in the application at runtime.
You can provide services to your dynamic components in these two ways. In my example I will demonstrate creating the component inside a container component, DynamicContainerComponent
.
First in the container component import all the services you will need. In my example AExampleService
and BExampleService
.
DynamicContainerComponent
import {
Component, ViewChild, AfterContentInit, ComponentFactoryResolver, Compiler, ViewContainerRef, NgModule, NgModuleRef,
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AExampleService } from './services/AExampleService';
import { BExampleService } from './services/BExampleService';
@Component({
selector: 'dynamic-container',
template: `<ng-container #vc></ng-container>`,
styleUrls: ['./dynamic-container.component.css']
})
export class DynamicContainerComponent implements AfterContentInit{
@ViewChild('vc', { read: ViewContainerRef }) _container: ViewContainerRef;
constructor(private aExampleService: AExampleService) { }
ngAfterContentInit(){
this.addDynamicComponent();
}
private addDynamicComponent(): void{...}
}
Now you can use the AExampleService
and BExampleService
by use of dependency injection in the dynamic component. This example shows two methods:
BExampleService
into the dynamic componentDynamicContainerComponent
into the dynamic component that will expose AExampleService
.Take a look at the code in private addDynamicComponent(): void{...}
addDynamicComponent()
private addDynamicComponent(): void{
@Component({
template: `<h2>This is a dynamic component</h2>`,
styleUrls: ['./dynamic.component.css']
})
class DynamicComponent {
constructor(
public _parent: DynamicContainerComponent,
private bExampleService: BExampleService) { }
private someFunctionA(): void {
this._parent.aExampleService.doSomthingA();
}
private someFunctionB(): void {
this.bExampleService.doSomthingB();
}
}
@NgModule({
imports: [
BrowserModule
],
declarations: [DynamicComponent],
}) class DynamicModule { }
const mod = this.compiler.compileModuleAndAllComponentsSync(DynamicModule);
const factory = mod.componentFactories.find((comp) =>
comp.componentType === DynamicComponent
);
this.cmpRef = this._container.createComponent(factory);
}
Notice that neither AExampleService
or BExampleService
were declared as providers of the dynamic component, but rather they are declared as providers to module that contains the DynamicContainerComponent
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With