2019年6月30日日曜日

AngularのdetectChanges()で「ViewDestroyedError: Attempt to use a destroyed」が発生した時の対応方法。


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

私の担当がいつの間にかAngular専任になっていますが・・・・今回もやっぱりAngularネタです。

Angularで、NgRxなどでAPIから値を取得した場合、そのままView(template・html)側にデータを流し込んであげれば、取得したデータは問題なく表示されます。
ところが、component(TypeScript)側で取得したデータをstore.selectで取得すると、View(template・html)側に表示データが反映されない場合があります。

うーん、言葉だけで説明するのが難しい。
この辺はいつかNgRxの使い方とかで詳しく説明したいですが、前者の場合、ストリーム(川の流れ)は繋ぎっぱなしですが、
後者は、一度ストリーム(川の流れ)から、データ取っているので、流れが止まっている、という事ですね。

強制的に画面に反映させる為には、「changeDetectorRef の detectChanges() 」メソッドを使います。

では、ここで使い方の例を一つ。
import { Component, ChangeDetectorRef, OnInit } from '@angular/core';
// (中略)
export class HogeKomaComponent implements OnInit {
// (中略)
  constructor(
    public store: Store,
    private changeDetectorRef: ChangeDetectorRef
  ) {}
 
  ngOnInit() {
    this.hogeKomaSubscription.push(
      this.store
        .select(fromHoge.getKomaList)
        .pipe(skip(1))
        .subscribe(result => {
            //
            // ここで取得したデータを編集し、Template側の変数へ再設定(これだけだと、画面は更新されない)
            //
 
            // 画面の表示を更新する(これを実施する事で画面が更新される)
            this.changeDetectorRef.detectChanges();
    }));
 
    // データ取得
    this.store.dispatch(new KomaListActions.GetKomaList());
  }

で、ここからが本題なのですが、「detectChanges()」を使っていると、以下のようなエラーが発生する事があります。
    common.96cfb6ba445916612966.js:1 ERROR Error: ViewDestroyedError: Attempt to use a destroyed view: detectChanges
    at pm (main.35927d7a5d9b4fa62e08.js:1)
    at Object.m_ [as updateDirectives] (main.35927d7a5d9b4fa62e08.js:1)
    at jv (main.35927d7a5d9b4fa62e08.js:1)
    at D_ (main.35927d7a5d9b4fa62e08.js:1)
    at Object.i_ [as checkAndUpdateView] (main.35927d7a5d9b4fa62e08.js:1)
    at n.detectChanges (main.35927d7a5d9b4fa62e08.js:1)
    at e._next (10.ab643854ddb1ed074304.js:1)
    at e.__tryOrUnsub (main.35927d7a5d9b4fa62e08.js:1)
    at e.next (main.35927d7a5d9b4fa62e08.js:1)
    at e._next (main.35927d7a5d9b4fa62e08.js:1)

エラーメッセージは、
ViewDestroyedError: Attempt to use a destroyed view: detectChanges
という事ですが、要は、「画面表示を行おうとしたけど、もう対象のViewが存在しない」という事ですね。

こういう場合は、
  if (!this.changeDetectorRef['destroyed']) {
    this.changeDetectorRef.detectChanges();
  }

上記のように、既にViewが破棄されていないか確認する事で回避出来ます。

今回も内容の割には長くなってしまいました・・・・
(エラーメッセージと対応内容書けば、ある意味終了なんですけどね。)

こんな内容でも、誰かの役に立つ事を願って・・・・

では、より良いAngularライフを!


Dockerの開発環境作成で発生した問題(BIOS is mandatory、bashエラー、no such file or directory 等)と、その対処方法。


オフィス狛 技術部のJoeです。

先日、Dockerによる開発環境を作成しました。
とはいっても、Docker初心者なので一から構築した訳でなく、既にymlファイルなどの定義は作成されていたので、必要なパッケージをインストールして起動するだけ。。。
のはずだったのですが、なぜか私の端末でのみいくつか問題が発生したので、対処方法と併せてご紹介します。

【環境】
・Windows10 Home
・Docker Toolbox 18.03.0-ce

問題1.仮想化を有効にできない。

まず、Docker用の仮想マシンを構築するため、「Docker Quickstart Terminal」を実行すると以下のエラーが発生しました。
Running pre-create checks...
Error with pre-create check: "This computer doesn't have VT-X/AMD-v enabled. Enabling it in the BIOS is mandatory"

すぐにBIOSで仮想化の有効化を忘れていたと思い、BIOSを起動しましたが、「VirtualizationTechnology」など、仮想化に関する項目が見当たりません。

これが意外と事例が無く、解決までに結構時間が掛かってしまったのですが、結局、BIOSをアップデートすることで仮想化の項目が現れ、有効化することができました。

参考までに、今回アップデートしたBIOS情報を載せておきます。
・BIOS:VC65-C1
・バージョン:更新前)0501 更新後)0801
・ダウンロード先:https://www.asus.com/jp/Mini-PCs/VivoMini-VC65-C1/HelpDesk_BIOS/


問題2.bashが実行できない。

仮想化を有効できたので、再度「Docker Quickstart Terminal」を実行すると、今度は以下のエラーが発生しました。
このショートカットは、リンク先の'bash.exe'が変更または移動されているので、正しく機能しません。

「Docker Quickstart Terminal」で実行される「start.sh」はbashなのですが、Docker Toolboxと一緒にインストールするGitの「bash.exe」を使用します。

こちらは、Docker Toolboxをインストールする前に、Gitを既にDドライブにインストールしていたことが原因でした。
「Docker Quickstart Terminal」のショートカットのリンク先、「bash.exe」のパスをCからDドライブに変更することで、エラーを解消できました。

問題3.コンテナが起動しない。

スタートからつまずきましたが、やっとコンテナの起動ということで、「docker-compose up」コマンドを実行したところ、以下のエラーで起動に失敗しました。

【コンテナのログ】
npm ERR! path /usr/src/app/package.json
npm ERR! code ENOENT
npm ERR! errno -2
npm ERR! syscall open
npm ERR! enoent ENOENT: no such file or directory, open '/usr/src/app/package.json'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

「package.json」が見つからないと言ってますが、コンテナにコピーした時にエラーは出てなく、npmのインストールも正常に実行できていました。

docker psコマンドでSTATUSを見ると、Restartingが繰り返されている状態になっています。
CONTAINER ID  IMAGE  COMMAND                CREATED         STATUS                          PORTS  NAMES
6438e1e2df74  test   "bash -c 'npm run de…" 29 seconds ago  Restarting (254) 2 seconds ago         test

エラーになったコマンド「docker-compose up」では、ymlファイルを2ファイル(共通、環境別用に分けている)指定していたのですが、定義内容を1ファイルにまとめて指定することで起動できました。

2ファイルで起動できなかった原因がどうしても見つからなかったので、こちらは引き続き調べてみたいと思います。