如何在Angular 8中为@ViewChild使用新的静态选项?


204

我应该如何配置新的Angular 8视图子级?

@ViewChild('searchText', {read: ElementRef, static: false})
public searchTextInput: ElementRef;

@ViewChild('searchText', {read: ElementRef, static: true})
public searchTextInput: ElementRef;

哪个更好?我什么时候应该使用static:truevs static:false

Answers:


237

在大多数情况下,您将需要使用{static: false}。像这样设置它可以确保找到依赖于绑定分辨率的查询匹配(例如结构指令*ngIf, etc...)。

何时使用的示例static: false

@Component({
  template: `
    <div *ngIf="showMe" #viewMe>Am I here?</div>
    <button (click)="showMe = !showMe"></button>
  ` 
})
export class ExampleComponent {
  @ViewChild('viewMe', { static: false })
  viewMe?: ElementRef<HTMLElement>; 

  showMe = false;
}

static: false会是在角9.读默认的备用行为更加这里这里

{ static: true }引入了该选项以支持动态创建嵌入式视图。当您动态创建视图并希望访问时TemplateRef,您将无法执行操作,ngAfterViewInit因为这会导致ExpressionHasChangedAfterChecked错误。将static标志设置为true将在ngOnInit中创建视图。

不过:

在其他大多数情况下,最佳做法是使用{static: false}

请注意,尽管该{ static: false }选项在Angular 9中将成为默认选项。这意味着不再需要设置静态标志,除非您要使用该static: true选项。

您可以使用angular cli ng update命令自动升级当前代码库。

有关迁移指南以及更多相关信息,可以在此处此处进行检查

静态查询和动态查询有什么区别?

@ViewChild()和@ContentChild()查询的静态选项确定查询结果何时可用。

使用静态查询(static:true),查询将在创建视图后解决,但要在更改检测运行之前进行。但是,结果永远不会更新以反映对视图的更改,例如对ngIf和ngFor块的更改。

对于动态查询(静态:false),查询分别在ngAfterViewInit()或ngAfterContentInit()之后解析为@ViewChild()和@ContentChild()。结果将针对视图的更改而更新,例如对ngIf和ngFor块的更改。


请更新angular文档的链接(发布后更改)angular.io/api/core/ViewChild#description
Sachin Gupta,

2
我无法访问childView的实例。它一直在说不确定。
Nesan Mano

您能否提供有关删除Angular 9中的static选项的信息的链接?
Alex Marinov

@AlexMarinov我已经更新了我的答案,以更加清楚角度9将会发生什么。有关此问题的链接在迁移指南中
Poul Kruijt,

1
@MinhNghĩa如果将整个组件嵌套在组件模板之外,则可以使用{ static: true },但是如果不需要直接访问内部的ViewChild ngOnInit,则应该使用{ static: false }
波尔克鲁伊特,

87

因此,根据经验,您可以执行以下操作:

  • { static: true }要访问ViewChildin 时需要设置ngOnInit

  • { static: false }只能在中访问ngAfterViewInit。当*ngIf模板中的元素上具有结构性指令(即)时,这也是您要追求的目标。


2
注意:在Angular 9中,静态标志默认为false,因此“可以安全删除任何{static:false}标志”。文档:angular.io/guide/static-query-migration
Stevethemacguy

17

从角度文档

静态 -是否在更改检测运行之前解析查询结果(即仅返回静态结果)。如果未提供此选项,则编译器将退回到其默认行为,即使用查询结果来确定查询解析的时间。如果任何查询结果在嵌套视图中(例如* ngIf),则将在运行更改检测后解决查询。否则,将在运行更改检测之前解决该问题。

这可能是一个更好的主意来使用static:true,如果孩子不依赖于任何条件。如果元素的可见性发生变化,则static:false可能会得到更好的结果。

PS:由于它是一项新功能,我们可能需要运行性能基准。

编辑

如@Massimiliano Sartoretto所述,github commit可能会为您提供更多见解。


3
我想在此功能后面添加官方动机github.com/angular/angular/pull/28810
Massimiliano Sartoretto

2

来到这里是因为在升级到Angular 8后,ngOnInit中的ViewChild为null。

静态查询在ngOnInit之前填充,而动态查询(静态:false)在之后填充。换句话说,如果在设置static:false后ngOnInit中的viewchild现在为null,则应考虑更改为static:true或将代码移至ngAfterViewInit。

https://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L332-L336

其他答案是正确的,并解释了为什么是这种情况:依赖于结构指令的查询(例如ngIf内的ViewChild引用)应在该指令的条件解决后(即,在检测到更改之后)运行。但是,可以安全地使用static:true,从而在ngOnInit之前解析查询以获取未嵌套的引用。恕我直言,这种特殊情况值得一提,因为空异常可能是您遇到这种特殊性的第一种方式,对我而言。


1

查看子@angular 5+令牌两个参数(“本地引用名称”,静态:false | true)

@ViewChild('nameInput', { static: false }) nameInputRef: ElementRef;

知道真假之间的区别检查此

静态-是否在更改检测运行之前解析查询结果(即仅返回静态结果)。如果未提供此选项,则编译器将退回到其默认行为,即使用查询结果来确定查询解析的时间。如果任何查询结果在嵌套视图中(例如* ngIf),则将在运行更改检测后解决查询。否则,将在运行更改检测之前解决该问题。


0

在ng8中,您可以手动设置何时访问父组件中的子组件。当将static设置为true时,这意味着父组件仅在onInit挂钩中获得该组件的定义:例如:

 // You got a childComponent which has a ngIf/for tag
ngOnInit(){
  console.log(this.childComponent);
}

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

如果static为false,则仅在ngAfterViewInit()中得到定义,在ngOnInit()中得到未定义。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.