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

时间:2016-11-11 07:53:46

标签: javascript angular

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

我总共使用了两种方式。

  1. ElementRef和querySelector
  2. 组件模板:

        `<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

    1. @ViewChild
    2. 组件模板:

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

4 个答案:

答案 0 :(得分:3)

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

仅当ngOnInit()被调用时,该值才在ngAfterViewInit()中设置。

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

  }
}

答案 1 :(得分:2)

如果您仅在某人与其互动时(例如点击它)或与其中的兄弟元素或子元素一起使用该元素,您可以将该元素与该事件一起传递。

模板:

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

在这些情况下。

答案 2 :(得分:0)

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

@ViewChild('button') button: elementRef;

console.log(this.button);

ID =&#39;按钮1&#39;,不是&#39;按钮&#39;?

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

答案 3 :(得分:0)

这并不是最好的,但是我使用[ngClass]代替了类似的情况* ngIf。 只需使用“ display:none”创建一个类,并在需要时隐藏元素。可以毫无问题地访问使用@ViewChild选择的元素。 现在,您可以在搜索更好的解决方案或更优雅的解决方案时使用这个小的“ hack”。 例如。

.hide-element{
    display: none;
}

<div class="test" [ngClass]="expr === 'yourTest' ? 'hide-element' : null">
  <a #b id="button1" (click)="onButton1(b)">button1</a>
</div>

如果您要处理一些异步返回,则可以使用异步管道

<div class="test" [ngClass]="(expr | async) === 'yourTest' ? 'hide-element' : null">
      <a #b id="button1" (click)="onButton1(b)">button1</a>
</div>

希望有帮助。