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
This behaviour can be achieved via a 'portal'. This is a useful and fairly common pattern in Angular applications. For example you may have a global sidebar outlet living near the top app level and then child components may specify a local
, as part of their overall template, to be rendered at this location.
Note that while the
may be defined outside of the file where the desired outlet is defined, it is still necessary to place the
inside the template of some component. This can be a minimalist component which is only responsible for wrapping the
, however it could equally be a complicated component where the
of interest only plays a minor part.
This code illustrates one possible basic implementation of a portal.
@Directive({
selector: '[appPortal]'
})
export class PortalDirective implements AfterViewInit {
@Input() outlet: string;
constructor(private portalService: PortalService, private templateRef: TemplateRef) {}
ngAfterViewInit(): void {
const outlet: PortalOutletDirective = this.portalService.outlets[this.outlet];
outlet.viewContainerRef.clear();
outlet.viewContainerRef.createEmbeddedView(this.templateRef);
}
}
@Directive({
selector: '[appPortalOutlet]'
})
export class PortalOutletDirective implements OnInit {
@Input() appPortalOutlet: string;
constructor(private portalService: PortalService, public viewContainerRef: ViewContainerRef) {}
ngOnInit(): void {
this.portalService.registerOutlet(this);
}
}
@Injectable({
providedIn: 'root'
})
export class PortalService {
outlets = new Map();
registerOutlet(outlet: PortalOutletDirective) {
this.outlets[outlet.appPortalOutlet] = outlet;
}
}
It works using three parts:
and takes as input the name of the outlet at which the content should be rendered.
, and defines the outlet.This may seem like a lot of work for something quite simple but once this plumbing is in place it is easy to (re)use.
// foo.component.html
Foo
RIGHT
In general it's not a great idea to reinvent the wheel though when there are already well-tested, documented and stable implementations available. The Angular CDK provides such an implementation and I'd advise to use that one rather than your own in practice.