[angular] How do you access the element HTML from within an Angular attribute directive?

The Angular docs provide an example for creating an attribute directive that changes the background color of an element:

https://angular.io/docs/ts/latest/guide/attribute-directives.html

<p myHighlight>Highlight me!</p>
import { Directive, ElementRef } from '@angular/core';

@Directive({ selector: '[myHighlight]' })

export class HighlightDirective {
    constructor(el: ElementRef) {
        el.nativeElement.style.backgroundColor = 'yellow';
    }
}

Can I also use el.nativeElement to get the content of the element (e.g. Highlight me!), modify this and update the element?

This question is related to angular

The answer is


This is because the content of

<p myHighlight>Highlight me!</p>

has not been rendered when the constructor of the HighlightDirective is called so there is no content yet.

If you implement the AfterContentInit hook you will get the element and its content.

import { Directive, ElementRef, AfterContentInit } from '@angular/core';

@Directive({ selector: '[myHighlight]' })

export class HighlightDirective {

    constructor(private el: ElementRef) {
        //el.nativeElement.style.backgroundColor = 'yellow';
    }

    ngAfterContentInit(){
        //you can get to the element content here 
        //this.el.nativeElement
    }
}

Base on @Mark answer, I add the constructor to directive and it work with me.

I share a sample to whom concern.

constructor(private el: ElementRef, private renderer: Renderer) {
}

TS file

@Directive({ selector: '[accordion]' })
export class AccordionDirective {

  constructor(private el: ElementRef, private renderer: Renderer) {
  }

  @HostListener('click', ['$event']) onClick($event) {
    console.info($event);

    this.el.nativeElement.classList.toggle('is-open');

    var content = this.el.nativeElement.nextElementSibling;
    if (content.style.maxHeight) {
      // accordion is currently open, so close it
      content.style.maxHeight = null;
    } else {
      // accordion is currently closed, so open it
      content.style.maxHeight = content.scrollHeight + "px";

    }
  }
}

HTML

<button accordion class="accordion">Accordian #1</button>
    <div class="accordion-content">
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quas deleniti molestias necessitatibus quaerat quos incidunt! Quas officiis repellat dolore omnis nihil quo,
        ratione cupiditate! Sed, deleniti, recusandae! Animi, sapiente, nostrum?
      </p>     
    </div>

Demo https://stackblitz.com/edit/angular-directive-accordion?file=src/app/app.component.ts


I suggest using Render, as the ElementRef API doc suggests:

... take a look at Renderer which provides API that can safely be used even when direct access to native elements is not supported. Relying on direct DOM access creates tight coupling between your application and rendering layers which will make it impossible to separate the two and deploy your application into a web worker or Universal.

Always use the Renderer for it will make you code (or library you right) be able to work when using Universal or WebWorkers.

import { Directive, ElementRef, HostListener, Input, Renderer } from '@angular/core';

export class HighlightDirective {
    constructor(el: ElementRef, renderer: Renderer) {
        renderer.setElementProperty(el.nativeElement, 'innerHTML', 'some new value');
    }
}

It doesn't look like Render has a getElementProperty() method though, so I guess we still need to use NativeElement for that part. Or (better) pass the content in as an input property to the directive.