如何选择* ngIf渲染的动态元素

正如下面提供的代码 . 我试图选择由ngIf生成的动态元素但是失败了 .

我总共用了两种方法 .

  • ElementRef和querySelector

组件模板:

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

组件类:

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'));
    }

输出结果为 null .

  • @ViewChild

组件模板:

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

组件类:

@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);
    }

输出结果为 undefined ;

有没有办法获得* ngIf生成的动态dom?


最后,问题已经通过@ViewChildren解决了 .

要记录更新的结果,必须使用单独的功能 .

例如:

错误的代码:

@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;
    }

正确的代码:

@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;
    }

回答(3)

3 years ago

*ngIf="expr" 表达式为false时,您无法获取该元素,因为该元素不存在 .

仅当 ngAfterViewInit() 被调用时,该值尚未在 ngOnInit() 中设置 .

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());
    });

  }
}

3 years ago

如果您仅在某人与其交互的时刻(例如,点击它)或者使用其中的兄弟元素或子元素时才需要该元素,则可以将该元素与该事件一起传递 .

模板:

<div class="test" *ngIf="expr">
  <a #b id="button1" (click)="onButton1(b)">button1</a>
</div>

码:

onButton1(button: HTMLButtonElement) {
}

如果您需要没有与之交互的元素,您也可以查看 ViewChildren 查询而不是 ViewChild .

您可以使用它进行设置

@ViewChildren('button') buttons: QueryList<ElementRef>;

然后,您可以通过 this.buttons.changes.subscribe(...) 订阅与选择器匹配的元素的更改 . 如果创建或删除元素,您将通过订阅收到通知 . 然而,我的第一种方法涉及更少的样板代码 .

另外,您也可以在确定元素存在的时刻(通过一些前提条件)同步访问 QueryList . 在您的示例中,您应该能够检索按钮

let button: ElementRef = this.buttons.first;

在这些情况下 .

3 years ago

<div class="test" *ngIf="boolean">
  <a #button id="button1">button1</a>
</div>

@ViewChild('button') button: elementRef;

console.log(this.button);

ID ='button1',而不是'按钮'?

var target = document.getElementById('Button1');