21
votes

With a structural directive, how would I get a hold of the (native) element the directive is on? With a normal directive, the ElementRef has it's nativeElement pointing to it - eg:

<input type="text" example>

@Directive({
  selector: '[example]'
})
export class ExampleDirective {    

  constructor( private el: ElementRef) {}

  ngAfterViewInit() {
    console.log(this.el.nativeElement); // the input
  }
}

But with a structural directive, it points to the template comment - eg.

<input type="text" *example>

@Directive({
  selector: '[example]'
})
export class ExampleDirective {

  constructor(
    private el: ElementRef,
    private view: ViewContainerRef,
    private template: TemplateRef<any>
  ) {}

  ngAfterViewInit() {
    this.view.createEmbeddedView(this.template);

    console.log(this.el.nativeElement); // template bindings comment
    // how to find the input itself?
  }
}

I've tried using various combinations of ViewContainerRef, TemplateRef, @ContentChild, @ViewChild - just don't seem to be able to find the input element itself...

4
consider this answer in another question stackoverflow.com/a/57796556/2145997 - s-f

4 Answers

13
votes

All structural directives are added to <ng-template> elements. Angular never adds <ng-template> elements to the DOM. Therefore it's not possible to get the element a structural directive is added to.

If you use the shorthand syntax with * like

<div *ngIf="..."></div>

angular creates

<ng-template [ngIf]="...">
  <div></div>
</ng-template>

and because <ng-template> is not added, there is no way of getting it and because <div> is not the element the structural directive is added to you also can't get this element using the directive reference.

3
votes

This isn't pretty, but worked for me:

this.viewContainer.get(0).rootNodes[0]

I used it when implementing a version of *ngIf directive but with animation: animatedIf.

0
votes

When the structural directive is used on HTMLElement, you will not get the reference to that element, as it is not rendered yet. The input text box is not rendered yet when you are trying to access it in your code console.log(this.el.nativeElement); // template bindings comment

Please refer the link below to know how structural directives in Angular work. https://angular.io/guide/structural-directives#the-asterisk--prefix

So to get the reference of the element, you can use attribute directive on the same element and do the things needed.

-1
votes

Based on the Structural Directives Documentation (not sure if it works, but maybe helps you):

<input type="text" *example>


@Directive({
  selector: '[example]'
})
export class ExampleDirective {

  constructor(private viewContainer: ViewContainerRef) { }

  @Input() set example() {
    console.log(this.viewContainer.element.nativeElement.value);
  }
}