Angular ViewChild / ViewChildren 實用技巧

Eric Li
hefemk
Published in
5 min readMar 27, 2021

前言

在 Angular,@ViewChild@ViewChildren 是很常用到的內建指令(Directive),它可以讓你取得子元件 (Child component) 或子元素 (Child element) 的參考。

基本用法:取得參考

來看個最簡單的例子,透過 ViewChild / ViewChildren 取得子元件的參考。

@ViewChild(SubComponent)
private subComp: SubComponent;
@ViewChildren(SubComponent)
private subComps: QueryList<SubComponent>;

你可以使用 privatepublic 修飾子來宣告變數。個人建議使用 private,這表示你可以將它侷限在目前的作用域當中,日後的改動也不容易對外產生破壞性變更。

實用方法:與 Setter 結合

實務上還有一種做法值得留意,那就是搭配 setter 使用的 ViewChild。它可以幫助你知曉欲抓取的目標物出現的時機,起到如 Lifecycle hook 的作用。這在一些動態產生元件 / 元素的場合會帶來不少益處,例如透過 ngFor 隨使用者操作重複渲染多個元件,你將可以準確抓到目標物渲染時機,進而對元件或元素實體進行操作。

private _myComp: MyComponent;@ViewChild(MyComponent)
private set myComp(comp: MyComponent) {
this._myComp = comp;
}
get myComp(): MyComponent {
return this._myComp;
}

小插曲:Private 與 Public

幾年前剛開始接觸 Angular 還是在 Dart 1.x 的時代,那時 ViewChild 必須裝飾在 public 變數上面,如今切換成 Angular TypeScript 則沒有這種限制。為了還原歷史,特別去找了一個非常古老的 Angular Dart repo 重現。若將 ViewChild 裝飾在 Private 變數上,得到如下的錯誤資訊:

EXCEPTION: Error in package:practice/user_list_component/user_list_component.html:9:4
ORIGINAL EXCEPTION: NoSuchMethodError: method not found: 'set$_userList' (t2.set$_userList is not a function)
ORIGINAL STACKTRACE:
TypeError: t2.set$_userList is not a function
at ViewAppComponent0.build$0 (http://localhost:8080/main.dart.js:29805:12)
at ViewAppComponent0.dart.AppView.create$2 (http://localhost:8080/main.dart.js:21270:21)
at ViewAppComponent0.create$2 (http://localhost:8080/main.dart.js:22429:21)
at _ViewAppComponentHost0.build$0 (http://localhost:8080/main.dart.js:29874:26)
at _ViewAppComponentHost0.dart.AppView.createHostView$2 (http://localhost:8080/main.dart.js:21276:21)
at _ViewAppComponentHost0.createHostView$2 (http://localhost:8080/main.dart.js:22442:21)
at ComponentFactory.create$2 (http://localhost:8080/main.dart.js:21572:53)
at ApplicationRefImpl_bootstrap_closure.call$0 (http://localhost:8080/main.dart.js:20367:22)
at ApplicationRefImpl_run_closure.dart.ApplicationRefImpl_run_closure.call$0 (http://localhost:8080/main.dart.js:20332:34)
at StaticClosure.dart._rootRun (http://localhost:8080/main.dart.js:6536:18)
ERROR CONTEXT:
Instance of 'DebugContext'

--

--