0

I have a custom directive that I'm trying to use to append an element to:

<ng-template #tooltipContent>
  <span>hello world</span>
</ng-template>

<button 
  tooltipText="tooltip text" 
  [appendedLinkElement]="tooltipContent" 
>
</button>

In my tooltip.directive.ts custom directive file I can successfully append text like so:

// ...
@Directive({
  selector: '[pslTooltip]',
  // ...
})
export class TooltipDirective ... {
  @Input('tooltipText') tooltipText: string;
  @Input() appendedLinkElement: TemplateRef<any>;
// ...
  constructor(private el: ElementRef, private renderer: Renderer2) { }

  create() {
    this.tooltip = this.renderer.createElement('span');

    this.renderer.appendChild(
      this.tooltip,
      this.renderer.createText(this.tooltipText) // ** this works, but how do I append the TemplateRef? 
    );

    this.renderer.appendChild(document.body, this.tooltip);
    // ...
  }
}

But when I try to replace the appendChild code from above example with the following, I get an error:

// attempt to append the `#tooltipContent` TemplateRef:
    this.renderer.appendChild(
      this.tooltip,
      this.appendedLinkElement,
    );
// I get a console error "TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'."

1 Answer 1

0

Credit: https://stackoverflow.com/a/50737839/11664580 Update the button to replace the two attributes with just one:

<button 
  tooltipContent="tooltip text" 
>

(alternatively, the attribute could be [tooltipContent]="tooltipContent", depending on if we want to pass a string or a template)

Update the .ts code as follows:

// ...
@Directive({
    selector: '[pslTooltip]',
    // ...
  })
  export class TooltipDirective ... {
    @Input('tooltipContent') set tooltipContent(value) {
        this._tooltipContent = value
        if (typeof this._tooltipContent !== 'string') {
          this.viewContainer.createEmbeddedView(this._tooltipContent)
        }
      }
  // ...
    constructor(private el: ElementRef, private renderer: Renderer2) { }
  
    create() {
        this.tooltip = this.renderer.createElement('span');

        if (typeof this._tooltipContent === 'string') {
          this.renderer.appendChild(
            this.tooltip,
            this.renderer.createText(this._tooltipContent) // textNode
          );
        } else {
          // If we are passing an ng-template:
          const embeddedViewRef = this.viewContainer.createEmbeddedView(this._tooltipContent);
          embeddedViewRef.rootNodes.forEach(n => {
            this.renderer.setAttribute(n, 'style', 'display: block!important;')
            this.renderer.appendChild(this.tooltip, n);
          });
        }
    
        this.renderer.appendChild(document.body, this.tooltip);
  }
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.