Angular - @ViewChildren-QueryList

Posted by Tim Lin on 2019-01-25

承接上一篇 @ViewChildren && ngAfterViewInit, 若要取得多個 child componet 值要使用 @ViewChildren

@ViewChildren 的使用

所以現在 template 改成有三個 <auth-message></auth-message>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template: `
<div>
<form (ngSubmit)="onSubmit(form.value)" #form="ngForm">
...
<auth-message
[style.display]="(showMessage ? 'inherit' : 'none')">
</auth-message>
<auth-message
[style.display]="(showMessage ? 'inherit' : 'none')">
</auth-message>
<auth-message
[style.display]="(showMessage ? 'inherit' : 'none')">
</auth-message>
....
</form>
</div>
`

想要取得這三個 <auth-message></auth-message> 的內容

使用 @ViewChildren 並存入 QueryList<AuthMessageComponent>

1
@ViewChildren(AuthMessageComponent) message: QueryList<AuthMessageComponent>;

並在 ngAfterViewInit() 對每個 message 做改變

1
2
3
4
5
6
7
ngAfterViewInit() {
if (this.message) {
this.message.forEach((message) => {
message.days = 30;
});
}
}

變更偵測 error

錯誤又來了! 這裡一樣會發生 變更偵測 error, 但其實這只會發生在 developement mode, 如果是 production mode 是會正常的

解決方法有兩種:

  1. 使用 setTimeout 可以解決
1
2
3
4
5
6
7
8
9
10
ngAfterViewInit() {
if (this.message) {

setTimeout(() => {
this.message.forEach((message) => {
message.days = 30;
});
});
}
}

  1. 使用 ChangeDetectorRef

    呼叫一次 detectChanges() 來觸發變更偵測,這時候變更偵測就只會被觸發一次,就不會有錯誤發生

    Referenced by: [Angular 大師之路] Day 25 - 效能調校之認識 ChangeDetectorRef

1
2
3
4
5
6
7
8
9
10
constructor(private cd: ChangeDetectorRef) {}

ngAfterViewInit() {
if (this.message) {
this.message.forEach((message) => {
message.days = 30;
});
this.cd.detectChanges();
}
}

同理 在上一篇 @ViewChildren && ngAfterViewInit 也可以這樣修改

1
2
3
4
5
6
7
8
constructor(private cd: ChangeDetectorRef) {}

ngAfterViewInit() {
if (this.message) {
this.message.days = 30;
}
this.cd.detectChanges();
}

Result

Reference