Reputation: 63
I have a ViewerWidgetComponent
- selector app-viewer-widget
, declared in and exported from SharedModule
.
The ViewerWidgetComponent
has a child component from a third party library: AcMapComponent
- selector ac-map
, where content is projected within ac-map
:
viewer-widget.component.html:
<ac-map [mapId]="viewerId">
<ng-container *ngIf="viewerInitialised | async">
<ng-container [ngTemplateOutlet]="content.templateRef"></ng-container>
</ng-container>
</ac-map>
Side note - template is used as content to be projected is conditionally rendered, found using custom ProjectContentDirective
directive.
ViewerWidgetComponent
has a ViewerConfiguration
provider, required for the third party AcMapComponent
viewer-widget.component.ts:
@Component({
selector: 'app-viewer-widget',
templateUrl: './viewer-widget.component.html',
styleUrls: ['./viewer-widget.component.scss'],
providers: [ViewerConfiguration],
})
export class ViewerWidgetComponent implements AfterViewInit {
@ContentChild(ProjectContentDirective) content!: ProjectContentDirective;
public viewerInitialised = new BehaviorSubject(false);
constructor(private viewerConfiguration: ViewerConfiguration) {
}
ngAfterViewInit(): void {
// other logic here...
this.viewerInitialised.next(true);
}
}
I am then importing this ViewerWidgetComponent
into ExploreModule
and using it in PortalComponent
.
PortalComponent
is declared in ExploreModule
:
portal.component.html:
<app-viewer-widget>
<ng-template appProjectContent>
<ac-layer>
<ac-billboard-desc></ac-billboard-desc>
</ac-layer>
</ng-template>
</app-viewer-widget>
Now the problem here, is ac-layer
is another third party component, which must be a child of the ac-map
component, as it relies on the providers array from the ac-map
component. Which it is, since it is in a template container and rendered via the ViewerWidgetComponent
, but since the template is in another module, DI is not picking up the ac-map
providers.
Snippet from third party ac-map
component ts:
@Component({
selector: 'ac-map',
template: `
<ng-content></ng-content>
`,
providers: [
CesiumService,
several more...
MapLayersService,
],
})
So Angular is throwing this error: NullInjectorError: R3InjectorError(ExploreModule)[MapLayersService -> MapLayersService -> MapLayersService -> MapLayersService]: NullInjectorError: No provider for MapLayersService!
Since it can't find the required providers, as ac-map
component is in a different module.
How can I forward the providers array within ac-map
, a child of ViewerWidgetComponent
, declared in SharedModule
, to be used in the PortalComponent
, which is in a different module?
Upvotes: 0
Views: 627
Reputation: 285
There's another way of creating dynamic component. If there was a running code snippet i could have tested but you can try this:
html
<ac-map [mapId]="viewerId" ProjectContentDirective>
</ac-map>
ts file:
@ViewChild(ProjectContentDirective) content!: ProjectContentDirective;
public viewerInitialised = new BehaviorSubject(false);
constructor(private componentFactoryResolver:ComponentFactoryResolver) { }
ngOnInit(): void {
this.viewerInitialised.subscribe(v=>{
if(v==true){
const viewContainerRef = this.content.viewContainerRef;
viewContainerRef.clear();
const componentRef = viewContainerRef.createComponent<AcMacCopmponent>(this.componentFactoryResolver.resolveComponentFactory(AcMacCopmponent));
}
})
}
ngAfterViewInit(): void {
// other logic here...
this.viewerInitialised.next(true);
}
Upvotes: 1