Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I select dynamic elements rendered by *ngIf

As the code provided bellow. I tried to select a dynamic element generated by ngIf but failed.

I used two ways in total.

  1. ElementRef and querySelector

component template:

    `<div class="test" *ngIf="expr">
      <a id="button">Value 1</a>
    </div>
    <div class="test" *ngIf="!expr">
      <a id="button">Value 2</a>
    </div>`

component class:

    expr: boolean;

    constructor(
      private elementRef: ElementRef,
    ) {
    }

    ngOnInit(): void{
    //Call Ajax and set the value of this.expr based on the callback;
    //if expr == true, then show text Value 1; 
    //if expr == false, then show text Value 2;
    }
    ngAfterViewInit(): void{
      console.log(this.elementRef.nativeElement.querySelector('#button'));
    }

The output result is null.

  1. @ViewChild

component template:

    `<div class="test" *ngIf="expr">
      <a #button>Value 1</a>
    </div>
    <div class="test" *ngIf="!expr">
      <a #button>Value 2</a>
    </div>`

component class:

    @ViewChild('button') button: elementRef;

    expr: boolean;

    ngOnInit(): void{
    //Call Ajax and set the value of this.expr based on the callback;
    //if expr == true, then show text Value 1; 
    //if expr == false, then show text Value 2;
    }

    ngAfterViewInit(): void{
      console.log(this.button);
    }

The out put result is undefined;

Is there a way to get dynamic dom generated by *ngIf?


Finally the problem has been solved through @ViewChildren.

And to log the updated result, it is necessary to use a separate function.

For example:

Wrong Code:

    @ViewChildren('button') buttons: ElementRef;

    function(): void{
      this.expr = true; // Change expression then the DOM will be changed;
      console.log(this.buttons.toArray()); // This is wrong because you will still get the old result;
    }

Right Code:

    @ViewChildren('button') buttons: ElementRef;

    function(): void{
      this.expr = true; // Change expression then the DOM will be changed;
    }
    ngAfterViewInit(): void{
      this.buttons.changes.subscribe( e => console.log(this.buttons.toArray()) ); // This is right and you will get the latest result;
    }
like image 747
Joe Avatar asked Nov 11 '16 07:11

Joe


People also ask

What is * ngIf and how does it work?

NgIflink. A structural directive that conditionally includes a template based on the value of an expression coerced to Boolean. When the expression evaluates to true, Angular renders the template provided in a then clause, and when false or null, Angular renders the template provided in an optional else clause.

Does ngIf remove element from DOM?

The ngIf directive removes or recreates a portion of the DOM tree based on an {expression}. If the expression assigned to ngIf evaluates to a false value then the element is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.

Does ngIf work on Div?

The Angular ngIf directive works essentially as an if statement for HTML, adding this missing feature to the language under the form of the special ngIf attribute. In this example, the container div will only be shown to the user if the user is logged in, otherwise the whole content of the div is not visible.

What happens when component is made visible again using ngIf?

Your div will be rendered and visible once the change detection is triggered. When a change is detected, the whole lifecycle is ran again. If you want to run something, you should hook on one of the events of the lifecycle.


1 Answers

You can't get the element when the *ngIf="expr" expression is false because then the element doesn't exist.

The value is not yet set in ngOnInit(), only when ngAfterViewInit() is called.

Plunker example

@Component({
  selector: 'my-app',
  template: `
    <div class="test" *ngIf="prop">
      <a #button id="button1">button1</a>
    </div>
    <div class="test" *ngIf="!boolean">
      <a id="button2">button2</a>
    </div>`
 ,
})
export class App {
  @ViewChild('button') button: ElementRef;

  prop:boolean = true;

  ngAfterViewInit() {
    console.log(this.button);
  }
}

Plunker example with ViewChildren

@Component({
  selector: 'my-app',
  template: `
    <button (click)="prop = !prop">toggle</button>
    <div class="test" *ngIf="prop">
      <a #button id="button1">button1</a>
    </div>
    <div class="test" *ngIf="!boolean">
      <a #button id="button2">button2</a>
    </div>`
 ,
})
export class App {
  @ViewChildren('button') button: QueryList<ElementRef>;

  prop:boolean = true;

  ngAfterViewInit() {
    console.log(this.button.toArray());
    this.button.changes.subscribe(val => {
      console.log(this.button.toArray());
    });

  }
}
like image 114
Günter Zöchbauer Avatar answered Oct 07 '22 13:10

Günter Zöchbauer