What are projectable nodes in angular2

angular, typescript

Solution

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

Problem

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.

Original source