angular2 how to use ng-template from a different file? When I place the ng-template within the same HTML where I use it works but when I move ng-template into a separate file th
Expanding on the answer by @peter554 for reasons of explanation and portability. This will let you use a template across components.
To use:
'app.module.ts'
import {NgModule} from '@angular/core';
import {
IdcPortalDirective, IdcTemplatePortalDirective,
PortalService
} from './idc-template-portal/idc-template-portal.component';
@NgModule({
declarations: [
IdcPortalDirective,
IdcTemplatePortalDirective
],
imports: [],
exports: [],
providers: [
PortalService
],
bootstrap: [AppComponent]
})
export class AppModule {}
'./idc-template-portal/idc-template-portal.component.ts'
import {
AfterViewInit,
Directive,
Injectable,
Input,
OnInit, Output,
TemplateRef,
ViewContainerRef
} from '@angular/core';
/*** Input Template ***/
/*** Template Contents ***/
@Directive({
selector: '[idcPortal]'
})
export class IdcPortalDirective implements OnInit {
@Input() outlet: string;
@Output() inlet: string = this.outlet;
constructor(private portalService: PortalService, public templateRef: TemplateRef) {}
ngOnInit():void {
this.portalService.registerInlet(this);
}
}
/*** Output Container ***/
/*** ***/
@Directive({
selector: '[idcPortalOutlet]'
})
export class IdcTemplatePortalDirective implements OnInit, AfterViewInit {
@Input() appPortalOutlet: string;
@Output() outlet: string = this.appPortalOutlet;
constructor(private portalService: PortalService, public viewContainerRef: ViewContainerRef) {}
ngOnInit():void {
this.portalService.registerOutlet(this);
}
ngAfterViewInit() {
this.portalService.initializePortal(this.appPortalOutlet);
}
}
@Injectable({
providedIn: 'root'
})
export class PortalService {
outlets = new Map();
inlets = new Map();
registerOutlet(outlet: IdcTemplatePortalDirective) {
this.outlets[outlet.outlet] = outlet;
}
registerInlet(inlet: IdcPortalDirective) {
this.inlets[inlet.inlet] = inlet;
}
initializePortal(portal:string) {
const inlet: IdcPortalDirective = this.inlets[portal];
const outlet: IdcTemplatePortalDirective = this.outlets[portal];
outlet.viewContainerRef.clear();
outlet.viewContainerRef.createEmbeddedView(inlet.templateRef);
}
}
He,@peter554, mentions reinventing the wheel in regards to the Angular CDK portals package. However, I find his/this implementation to make more sense in the way it's used in the application flow and the ease in which a template can be ported from component to another component that contains the portal outlet (allowing component to component->portal template communication. For example within a component template implementing the Angular Material MatBottomSheet (idcBottomSheet)).
The 'input' element:
The 'output' element (inside your MatBottomSheet component template):