问题

在模板中显示相应的元素后获得@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()
     }
  }
}

其他回答

对于Angular 8——混合了null检查和@ViewChild static:错误的黑客

用于等待异步数据的分页控件

@ViewChild(MatPaginator, { static: false }) set paginator(paginator: MatPaginator) {
  if(!paginator) return;
  paginator.page.pipe(untilDestroyed(this)).subscribe(pageEvent => {
    const updated: TSearchRequest = {
      pageRef: pageEvent.pageIndex,
      pageSize: pageEvent.pageSize
    } as any;
    this.dataGridStateService.alterSearchRequest(updated);
  });
}

我自己在使用Angular 10时也遇到了同样的问题。

如果我尝试使用[hidden]或*ngIf,那么@ViewChild变量总是未定义的。

<p-calendar #calendar *ngIf="bShowCalendar" >
</p-calendar>

我没有把它从网页上删除。 我使用了一个[ngClass]使控件的透明度为:0,并将它完全移开。

<style>
  .notVisible {
    opacity: 0;
    left: -1000px;
    position: absolute !important;
  }
</style>

<p-calendar #calendar [ngClass]="{'notVisible': bShowCalendar }" >
</p-calendar>

我知道,这很蠢很丑,但它解决了问题。

我还必须让控制变成静态的。我不明白为什么…但是,再一次,它拒绝在没有改变的情况下工作:

export class DatePickerCellRenderer {
    @ViewChild('calendar', {static: true }) calendar: Calendar;

8 +基础

你应该添加{static: false}作为@ViewChild的第二个选项。这会导致在更改检测运行后解析查询结果,允许在值更改后更新@ViewChild。

例子:

export class AppComponent {
    @ViewChild('contentPlaceholder', { static: false }) contentPlaceholder: ElementRef;

    display = false;

    constructor(private changeDetectorRef: ChangeDetectorRef) {
    }

    show() {
        this.display = true;

        // Required to access this.contentPlaceholder below,
        // otherwise contentPlaceholder will be undefined
        this.changeDetectorRef.detectChanges();

        console.log(this.contentPlaceholder);
    }
}

Stackblitz示例:https://stackblitz.com/edit/angular-d8ezsn

我们遇到了在*ngIf上设置tabindex的情况

html:

<div #countryConditional1 *ngIf="country=='USA'">                        
  <input id="streetNumber" [(ngModel)]="streetNumber" pInputText>
</div>

ts:

@ViewChild('countryConditional1') set countryConditional1(element) {
  if (element) {
    const container2 = document.querySelector("#someElement");
    container2.querySelector("span > input").setAttribute("tabindex", "18");
  }

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

首先注入ChangeDetectorRef:

constructor(private changeDetector : ChangeDetectorRef) {}

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

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