4

I'm trying to create a fairly basic directive that can either, hide (remove from DOM), show, or show and disable content inside it depending on user permissions.

As per the angular guide I should be able to do something similar to this to modify content inside a directive.

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

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
    constructor(el: ElementRef) {
       el.nativeElement.style.backgroundColor = 'yellow';
    }
}

However I am having a problem accessing the inner content of the directive. This needs to be a structural directive in order to be able to remove the content from the DOM, but when I make it a structural directive ElementRef only returns a HTML comment element containing the ng bindings, it does not return the actual content.

When I test this as a non-structural directive it returns the actual content.

How do I access the inner content of a structural directive?

1
  • If you're using angular then you would need to be familiar with html *ngIf and <ng-template #id> Commented Nov 13, 2018 at 9:59

3 Answers 3

13

I think you're mixing them all together.

A structural directive is a directive made to manipulate the DOM itself : it can append or remove a whole section of the DOM based on conditions.

An attribute directive is a directive made to change an element of the DOM. It can change its style, but it can't delete it from the DOM (but can hide it with CSS though).

They have a dedicated purpose and can't (well, shouldn't) try to do what the other is supposed to do. They also have different syntaxes due to their purpose.

If you look at this stackblitz you will see the difference between both : one can display the element reference (attribute), the other will only display an HTML comment (structural).

The structural directive is used in a reserved space in the HTML and is aware only of that space.

If you wish to get the element reference of the element that has the structural directive, you will need to use the nextElementSibling of the comment to get it.

But then again, just look at the blitz, and see for yourself !

Sign up to request clarification or add additional context in comments.

4 Comments

This makes sense and the stackblitz you linked is producing the same results I got when testing. However do you have a source (ideally from the angular documentation) that says a structural directive cannot/should not also be able to modify the element as well as remove or append it? You might be right and the answer might just be that its not possible. However I was hoping there would be a way as (in my opinion) it is more elegant than using 2 separate directives.
The source is the code itself : structural directives have a particular syntax, starting with *. In case you're not aware, this is a microsyntax that replaces the current tag with a ng-template. The documentation explains that so I won't repeat it, sorry, but to be precise, it's not explicitly said : it's just that you can't append custom directives to ng-template tags, because they serve a specific purpose that Angular handles.
@JacobRegan and to answer your last point, nothing prevents you from using a custom component with both the structural and attribute directives in it !
For my test case (Angular 18) it seems to be the previousElementSibling, not the next.
0

Try this

constructor(private elementRef: ElementRef) {}

ngAfterViewInit() {
    this.elementRef.nativeElement.style.backgroundColor = 'yellow';
}

1 Comment

I've tried this, this.elementRef.nativeElement returns a html comment only. This works fine with a normal directive (e.g. <div myDirective></div>) but it doesn't work with a structural directive (e.g. <div *myDirective></div>)
0

It's possible to catch it as you made. But you have just move the operations in the ngOnInit like this.

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

@Directive({
   selector: '[appHighlight]' 
})
export class HighlightDirective implements OnInit{
    constructor(el: ElementRef) { }

    ngOnInit() {
       this.el.nativeElement.style.backgroundColor = 'yellow';
    }

 }

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.