Search code examples
angulartemplatesangular2-directives

Angular 2 - Create a Tree component - Struggling with structural directives


I try to create a tree of divs with a text (will be more complex eventualy) inside with a structural directive.. and it should render something like this,

<div>Campaign
  <div>Leaf A</div>
  <div>Leaf B</div>
</div>
<div>Customer
    <div>Parameters</div>
    <div>Segments</div>
    <div>Products</div>
</div>

but so far I get nested divs that are empty

here is the html template using that directive

<div *siteMapLeaf="'Campaign'">
     <div *siteMapLeaf="'Leaf A'"></div>
     <div *siteMapLeaf="'Leaf B'"></div>
</div>
<div *siteMapLeaf="'Customer'">
     <div *siteMapLeaf="'Parameters'"></div>
     <div *siteMapLeaf="'Segments'"></div>
     <div *siteMapLeaf="'Products'">
</div>

here is the directive I use:

@Directive({ selector: '[siteMapLeaf]' })
export class SiteMapDirective
{
    constructor(
        private templateRef: TemplateRef < any > , // content what is inside ng-Template, ie the div referenced by the directive
        private viewContainer: ViewContainerRef
    ) {}

    @Input() set siteMapLeaf(caption)
    {
        let captionView=this.templateRef.createEmbeddedView(caption);
        this.viewContainer.insert(captionView);
    }

}

thanks


Solution

  • Your templates don't have any text nodes that would render caption. They only consist of empty div element.

    One way to achieve your requirentments is using Renderer2 as follows:

    @Directive({ 
      selector: '[siteMapLeaf]' 
    })
    export class SiteMapDirective {
      constructor(
        private renderer: Renderer2,
        private templateRef: TemplateRef <any>,
        private viewContainer: ViewContainerRef
      ) {}
    
      @Input() set siteMapLeaf(caption) {
        let captionView = this.templateRef.createEmbeddedView({});
        const parentNode = captionView.rootNodes[0];
        this.renderer.insertBefore(
              parentNode, this.renderer.createText(caption), parentNode.firstChild);
        this.viewContainer.insert(captionView);
      }
    }
    

    Here's an Stackblitz example