问题

在模板中显示相应的元素后获得@ViewChild的最优雅的方式是什么?

下面是一个例子。也可提供活塞。

Component.template.html:

<div id="layout" *ngIf="display">
  <div #contentPlaceholder></div>
</div>

Component.component.ts:

export class AppComponent {

    display = false;
    @ViewChild('contentPlaceholder', { read: ViewContainerRef }) viewContainerRef;

    show() {
        this.display = true;
        console.log(this.viewContainerRef); // undefined
        setTimeout(() => {
            console.log(this.viewContainerRef); // OK
        }, 1);
    }
}

我有一个默认隐藏其内容的组件。当有人调用show()方法时,它变得可见。然而,在Angular 2变更检测完成之前,我不能引用viewContainerRef。如上所示,我通常将所有必需的操作包装到setTimeout(()=>{},1)中。有没有更正确的方法?

我知道ngAfterViewChecked有一个选项,但它会导致太多无用的调用。

答案(设置)


当前回答

确保将参数{static: false}传递给@ViewChild可以解决这个问题。

template.html代码

<div *ngIf="showFirtChild">
  <first-child #firstchildComponent ></first-child>
</div>

在.ts文件

export class Parent implements {
  private firstChild: FirstchildComponent;

  @ViewChild('firstchildComponent', { static: false }) set content(content: 
  FirstchildComponent) {
     if(content) { 
          this.firstchildComponent = content;
     }
  }

  ShowChild(){
     this.showFirtChild = true;
     if(this.firstchildComponent){
        this.firstchildComponent.YourMethod()
     }
  }
}

其他回答

为ViewChild使用setter:

 private contentPlaceholder: ElementRef;

 @ViewChild('contentPlaceholder') set content(content: ElementRef) {
    if(content) { // initially setter gets called with undefined
        this.contentPlaceholder = content;
    }
 }

一旦*ngIf变成true, setter就会被元素引用调用。

注意,对于Angular 8,你必须确保设置{static: false},这是其他Angular版本的默认设置:

 @ViewChild('contentPlaceholder', { static: false })

注意:如果contentPlaceholder是一个组件,你可以改变ElementRef到你的组件类:

  private contentPlaceholder: MyCustomComponent;

  @ViewChild('contentPlaceholder') set content(content: MyCustomComponent) {
     if(content) { // initially setter gets called with undefined
          this.contentPlaceholder = content;
     }
  }

正如其他人提到的,最快的解决方案是使用[hidden]而不是*ngIf。采用这种方法,组件将被创建但不可见,因此您可以访问它。这可能不是最有效的方法。

确保将参数{static: false}传递给@ViewChild可以解决这个问题。

template.html代码

<div *ngIf="showFirtChild">
  <first-child #firstchildComponent ></first-child>
</div>

在.ts文件

export class Parent implements {
  private firstChild: FirstchildComponent;

  @ViewChild('firstchildComponent', { static: false }) set content(content: 
  FirstchildComponent) {
     if(content) { 
          this.firstchildComponent = content;
     }
  }

  ShowChild(){
     this.showFirtChild = true;
     if(this.firstchildComponent){
        this.firstchildComponent.YourMethod()
     }
  }
}

另一个快速的“技巧”(简单的解决方案)是使用[hidden]标签而不是*ngIf,重要的是要知道,在这种情况下,Angular会构建对象并在类下绘制它:隐藏,这就是ViewChild工作没有问题的原因。 所以重要的是要记住,你不应该在沉重或昂贵的物品上使用隐藏,这会导致性能问题

  <div class="addTable" [hidden]="CONDITION">

解决这个问题的另一种方法是手动运行更改检测器。

首先注入ChangeDetectorRef:

constructor(private changeDetector : ChangeDetectorRef) {}

然后在更新控制*ngIf的变量后调用它

show() {
        this.display = true;
        this.changeDetector.detectChanges();
    }