4

I'm trying to pass a ng-template to my directive, something like this:

component.html

<div myDirective [myTemplate]="myTemplate"></div>
<ng-template #myTemplate><p>Lorem ipsum dolor sit amet.</p></ng-template> 

directive.ts

import {Directive, Input} from "@angular/core"

@Directive({
  selector: "[myDirective]"
})
export class MyDirective {
  @Input() myTemplate

  ngOnInit () {
    console.log(this.myTemplate.elementRef.nativeElement)
  }
}

But it just shows <!-- -->. How do I access the contents of the template? None of the other properties seem to have it - comments on this question suggest using templateRef instead, but it's undefined.

Stackblitz if needed.

To clarify, the ultimate goal of the directive is to conditionally add the contents of the template to its parent element (along with some other changes).

John Montgomery
  • 6,739
  • 9
  • 52
  • 68
  • you should use it as `*myTemplate` instead of `[myTemplate]` that way the structural directive receives what you intend. If you try to use a template inside I suggest @ContentChild or some sort. Not posting as answer as its not – Francisco Santorelli May 16 '19 at 22:38
  • @FranciscoSantorelli Then I get "Can't bind to 'myTemplate' since it isn't a known property of 'div'." And `@ContentChild` doesn't do what I want, I want the template to be reusable so it has to be accessible from outside the directive. – John Montgomery May 16 '19 at 22:46
  • I'm not sure what you try to achieve. Are you trying to get a reusable template that your directive will inject(?), or are you trying to pass to the directive a template that will do something? – Francisco Santorelli May 16 '19 at 22:49
  • @FranciscoSantorelli The ultimate goal of the directive is to conditionally add the contents of the template to its parent element (along with some other changes). – John Montgomery May 17 '19 at 17:18

2 Answers2

1

As you can see in angular.io :

The ng-template is an Angular element for rendering HTML. It is never displayed directly. In fact, before rendering the view, Angular replaces the ng-template and its contents with a comment.

So at the runtime, ng-template is just a comment. It is not renderable as a DOM and it's impossible to reach it as ElementRef type.

But if you want to send for example a p element to your directive, it's possible. I changed your code to do that. See this stackblitz project:

https://stackblitz.com

1252748
  • 14,597
  • 32
  • 109
  • 229
Max Hesari
  • 631
  • 6
  • 10
  • I know it works with regular elements, but I need to use a template because I don't want it to render in the parent component. I may just have to do that and use CSS to hide it or something if there's no way to do it with a template, but it isn't ideal. – John Montgomery May 17 '19 at 17:14
0

I have a popup-directive to handle positioning of popups in the dom. I place the directive on a button or link and pass it the popup element. The directive then positions the popup in the dom.

The directive supports both a regular html element and a ng-template element as a popup.

For clarity, the code below contains only parts relevant for the question.

import { Directive, ElementRef, Input, OnInit, TemplateRef, ViewContainerRef } from "@angular/core";
    
    
@Directive({
    selector: '[ui-popup]'
})
export class UIPopupDirective implements OnInit, OnDestroy {
      
  constructor(private el: ElementRef, private containerRef: ViewContainerRef) { }

  @Input() popupTemplate: HTMLElement;
  @Input() popupNgTemplate: TemplateRef<any>;
  @Input() data:any;
  
  ngOnInit() {
     if (this.popupNgTemplate) {
      const embeddedViewRef = this.containerRef.createEmbeddedView(this.popupNgTemplate, {
        item: this.data
      });
      embeddedViewRef.detectChanges();
      this.popupTemplate = embeddedViewRef.rootNodes[0];
    }
}

Examples of usage:

<button type="button" ui-popup [popupTemplate]="regularTag">Click to say hello</button>

<div #regularTag>Hello</div>

... or ...

<button type="button" ui-popup [popupNgTemplate]="ngTemplateTag">Click to discover the world</button>

<ng-template #ngTemplateTag><div>World</div></ng-template>
Jette
  • 2,459
  • 28
  • 37