見出し画像

プログラマ探偵の事件簿:DataTablesで列の数を変更するとUnhandled Promise Rejection: TypeError: undefined is not an object (evaluating 'headerCells[i].style')

新人助手の猫さんがやってきて1ヶ月半、仕事に慣れてきたころの事件である。

事件の始まり

シン・TWSNMPのMIBブラウザーを改善しようとしていた時のことである。MIBを取得していると謎のハングアップが発生することに気付いた。

猫のアニメが表示されたままになってしまう。ブラウザーの開発者ツールで見ると

Unhandled Promise Rejection: TypeError: undefined is not an object (evaluating 'headerCells[i].style')

のエラーである。何となくテーブルの列に関係していそうであった。

テーブルの列数が変わった時に発生する

発生する条件を探るために試行錯誤していると、どうやらMIBを表示するためのテーブルの列数が変わった時に発生するようである。

のような3列のMIBを表示した後、

4列あるMIBを表示するような場合や、その逆である。
テーブルの列数が変わらない時は発生しない。

謎を解く鍵はDataTablesの削除にあった

MIBを表示するテーブルは DataTables

を使って表示している。MIBを取得する毎にテーブルを再作成するようにしている。

 const showTable = () => {
    if (table && DataTable.isDataTable("#mibTable")) {
      table.clear();
      table.destroy();
      table = undefined;
    }
    table = new DataTable("#mibTable", {
      columns: columns,
      data: data,
      language: getTableLang(),
      select: {
        style: "single",
      },
    });
 

前に表示したテーブルがあれば、削除してから再度作成するような仕組みである。ソースコード上も、そういう動作に見える。しかし、実際はそうではなかった。亡霊のようにテーブルは残っていて列の数を変えると悪さをするのである。

table.destroy()では消えない

table.destroy()でテーブルがなくなると信じていたが、消えてはいなかったのだ!!
DataTables のマニュアルを読むとtable.destroy(true)という方法を見つけた。試してみるとテーブルの亡霊は消えるが2回目にテーブルが作成できない別の問題が発生した。
ここから、テーブルを消す方法を探すための長い試行錯誤が始まった。いつものようにGoogleさんから教えてもらった方法をいろいろ試すがテーブルの亡霊は消えない。テーブル全部ではなく、列だけ変更する方法も調べたが、それもできなないようである。テーブルを削除して作り直す方法が見つかり振り出しに戻る。諦めて寝ることにした。

table.destroy(true)でリベンジ

朝起きて、新人助手の猫さんが私の部屋までやって来て
がんばって、昨日の問題を解決するのよ!
と言った。
table.destroy(true) に再挑戦することにした。
table.destroy(true) の動作を観察するとテーブルを表示したいところ書いた

<table id="mibTable" class="display compact" style="width:99%" />

がテーブルを作成した時点でなくなっていることに気づいた。2回目に作成する時にはテーブルを作成する場所がなくなっているためにテーブルが表示されなくなる。作成する場所も再作成すればいけそうな気がした。

    <div id="table">
      <table id="mibTable" class="display compact" style="width:99%" />
    </div>

消えない大元の場所の中に、消えてもよいテーブルの場所を作って

    if (table && DataTable.isDataTable("#mibTable")) {
      table.clear();
      table.destroy(true);
      table = undefined;
      const e = document.getElementById("table");
      if(e) {
        e.innerHTML = `<table id="mibTable" class="display compact" style="width:99%" />`;
      }
    }
    table = new DataTable("#mibTable", {
      columns: columns,
      data: data,
      language: getTableLang(),
      select: {
        style: "single",
      },
    });

のようにテーブルを作成する場所も再作成するようにして解決した。

消したと思っても亡霊のように悪さをするオブジェクトもある!
と先代の助手の猫が天から言っている。


開発のための諸経費(機材、Appleの開発者、サーバー運用)に利用します。 ソフトウェアのマニュアルをnoteの記事で提供しています。 サポートによりnoteの運営にも貢献できるのでよろしくお願います。