On reading the documentation of ViewContainerRef and ComponentFactory, where , for example we have the method
ViewContainerRef#createComponent which takes 3 arguments : componentFactory
, injector
and projectableNodes
.
I have tried looking up what projectableNodes
mean and how they are used in blogs, tutorials and source code but could not find much.
On looking up the diff for for ngComponentOutlet directive, All I could gather was that the string in projectableNodes is "projected" or rendered on to the created components view ( like ng-content may be). If so that is confusing as we have ViewContainerRef#createEmbeddedView for the same.
I would like to know as to what are these projectedNodes
and have an example of their usage.
Projectable nodes are the node elements ( i.e elements implementing the node interface ), which are "projected" or in other words, transcluded onto the ng-content
that we have in the template of our component.
For example we can create a node element the following way :
var myNode = document.createElement('div');
var text = document.createTextNode('this is my text');
myNode.appendChild(text);
Then we can use the above node, the following way :
constructor(private vcr:ViewContainerRef ) {
}
ngAfterViewInit() {
let cmpFactory = this.vcr.resolveComponentFactory(MyDynamicComponent);
let injector = this.vcr.parentInjector;
var myNode = document.createElement('div');
var text = document.createTextNode('this is my text');
myNode.appendChild(text);
this.vcr.createComponent(cmpFactory,0,injector,[ [ myNode ] ])
}
A two dimensional array is accepted for projected nodes as we can have multi-slot transclusion, that is more than one ng-content
.
Here is a full example of how to use the projectable nodes with ViewContainerRef#createComponent
. This example dynamically creates a component that has transclsion/ng-content in it:
import { Component, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
import { ComponentFactory,ComponentRef, Renderer } from '@angular/core';
@Component({
selector: 'sample',
template: '<ng-content></ng-content><ng-content></ng-content>'
})
export class Sample { }
@Component({
selector: 'demo',
template: '<p>Demo</p>',
entryComponents: [Sample]
})
export class DemoComponent {
constructor(private vcr: ViewContainerRef, private cfr: ComponentFactoryResolver, private r: Renderer) { }
ngAfterViewInit() {
let cmpFactory = this.cfr.resolveComponentFactory(Sample);
let injector = this.vcr.parentInjector;
let demoCompEl = this.vcr.element.nativeElement;
let projectedElA = this.r.createElement(demoCompEl,'p');
this.r.createText(projectedElA,'projectable content A');
this.r.detachView([projectedElA]);
let projectedElB = this.r.createElement(demoCompEl,'p');
this.r.createText(projectedElB,'projectable content B');
this.r.detachView([projectedElB]);
let projectedC = document.createElement('div');
let text = document.createTextNode('projectable content C');
projectedC.appendChild(text);
let cmpRef = this.vcr.createComponent(cmpFactory,0,injector,[[projectedElA],[projectedElB,projectedC]]);
}
}
Output :
Demo
projectable content A
projectable content B
projectable content C
The additonal thing to notice is that in the 2d array that we pass for projectable nodes, each 1d array entry has the root elements of a particular view that belong together/ will be rendered together in a single ng-content
block
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