[Ionic] native api 無法觸發angular change detection問題
最近寫app時發現當使用native api時,有時候會無法觸發angular change detection
像是qr scanner啟動相機時,因為scanner放在app最下層,用ngIf可以app畫面隱藏起來,但關閉scanner卻無法再顯示
或是偵測mobile keyboard顯示要隱藏按鈕時,ngIf完全無效
查了ionic forums發現不少人在呼叫ntaive api時都有各種無法觸發angular change detection問題
其原因是這些native api是run outside angular zone,可以用NgZone.isInAngularZone()檢查
以qr scanner為例如下,會發現開啟scanner時還是在angular zone中,但關閉時卻不在angular zone裡,導致change detection未觸發
this.qrScanner.prepare()
.then((status: QRScannerStatus) => {
if (status.authorized) {
// camera permission was granted
this.qrScanner.show();
this.hideApp = true; // trigger ngIf to hide App
console.log(NgZone.isInAngularZone()); // true
// start scanning
this.scanSub = this.qrScanner.scan().subscribe((text: string) => {
console.log(NgZone.isInAngularZone()); // false
this.qrScanner.hide(); // hide camera preview
this.hideApp = false; // not trigger ngIf, App not show
this.qrScanner.destroy();
if (this.scanSub) this.scanSub.unsubscribe(); // stop scanning
});
} else if (status.denied) {
this.qrScanner.openSettings();
}
})
.catch((e: any) => console.log('Error is', e));
解決方法有兩種
將要觸發ngIf的變數放到ngZone.run裡:
this.ngZone.run(() => this.hideApp = false)
或是加上ChangeDetectorRef.detectChanges
this.qrScanner.hide(); // hide camera preview
this.hideApp = false; // not trigger ngIf, App can't appear
this.qrScanner.destroy();
if (this.scanSub) this.scanSub.unsubscribe(); // stop scanning
this.changeDetectorRef.detectChanges(); // 加上這段
參考資料
Angular Change Detection - How Does It Really Work ?
Stackoverflow - Angular2 zone.run() vs ChangeDetectorRef.detectChanges()