[Ionic] native api 無法觸發angular change detection問題

[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(); // 加上這段

 

參考資料

Ionic forums

Angular Change Detection - How Does It Really Work ?

Stackoverflow - Angular2 zone.run() vs ChangeDetectorRef.detectChanges()