问题形容
我有这样一个 Angular Component,模板文件如下:
@Component({
selector: 'example-app',
template: `
<pane id="1" *ngIf="shouldShow"></pane><pane id="2" *ngIf="!shouldShow"></pane><button (click)="toggle()">Toggle</button><div id="panel 1?" #pane999>1</div><div id="panel 2?" pane>2</div><div>Selected: {{selectedPane}}</div>
`,
})
在其 Component 实现里,我冀望通过 `@ViewChild`,在运行时拿到 id 为 `panel 1?` 的 div 元素的实例。
export class ViewChildComp {
constructor(public changeDetectorRef: ChangeDetectorRef
){}
@ViewChild("panel 1?")
set panethis(v) {
//setTimeout(()=> this.selectedPane = v.id, 0);this.selectedPane = v.id;this.changeDetectorRef.detectChanges();//Promise.resolve().then(() => this.selectedPane = v.id);
}
然而运行时没有失去冀望的后果,报错:> ERROR TypeError: Cannot read properties of undefined (reading 'id') at ViewChildComp.set (ng-content.component.ts:57:27) at ViewChildComp_Query (template.html:3:5) at executeViewQueryFn (core.js:8758:5) at refreshView (core.js:7437:13) at refreshComponent (core.js:8527:13) at refreshChildComponents (core.js:7186:9) at refreshView (core.js:7430:13) at refreshComponent (core.js:8527:13) at refreshChildComponents (core.js:7186:9) at refreshView (core.js:7430:13)# 问题剖析咱们点击上图高亮的 `template.html` 调用栈:来到咱们本人 Component 的模板文件,因为这是一个内联到 Component 里的模板,所以显示为 `template.html` :通过单步调试,能发现在 `refreshView` 里,执行 `view query` 的入口逻辑:
function executeViewQueryFn(flags, viewQueryFn, component) {
ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');setCurrentQueryIndex(0);viewQueryFn(flags, component);
}
依据关键字 `view query` 查问 Angular 官网,发现在 view query 里应用 id 选择器的正确语法,并不是间接查问 HTML 元素的 id 属性,而是须要在 HTML 元素或者 `ng-template` 里应用符号 `#` 指定一个 id,而后将这个 id 传入 `@ViewChild`:批改之后的运行成果:# 总结view query 在父 Component 须要拜访其子 Component 的场景下特地有用。假如有一个 alert Component:
@Component({
selector: 'alert',
template: `
<h1 (click)="alert()">{{type}}</h1>
`,
})
export class AlertComponent {
@Input() type: string = "success";
alert() {
console.log("alert");
}
}
在咱们的父 Component 里,能够定义 AlertComponent 的多个实例:
@Component({
selector: 'my-app',
template: `
<alert></alert><alert type="danger"></alert><alert type="info"></alert>
`,
})
export class App {
@ViewChildren(AlertComponent) alerts: QueryList<AlertComponent>
ngAfterViewInit() {
this.alerts.forEach(alertInstance => console.log(alertInstance));
}
}
咱们能够应用 @ViewChildren 装璜器从宿主视图中抓取元素。@ViewChildren 装璜器反对指令或组件类型作为参数,或模板变量的名称。当参数是组件/指令时,返回值将是组件/指令实例。下面例子的 console.log 语句会打印 AlertComponent 的实例: