💄

kintoneでサブテーブルを装飾する

2022/11/23に公開

kintoneでサブテーブルを装飾するカスタマイズを実装する方法を順序立てて解説します。

Disclaimer

  • この記事に記載されているコードは適当に書いたので、タイポ等している可能性があります。また、堅牢さを気にせずに書いていますので、状況に応じて細かく変数の存在チェックを入れるなどしましょう。
  • この記事に記載されているコードはフォーマットされていないので、インデント等が統一されていない可能性があります。
  • 記事を読みやすくするために、記載されているコードの一部を割愛する場合があります。

1. 装飾するサブテーブルのclass属性を取得する

kintoneのJavaScript APIにはサブテーブルの要素を取得するようなAPIはたぶんありません(あったら教えてほしい)。なので、Chrome Dev Tools等でサブテーブルのtableタグに付与されているclass属性を参照し、控えておきます。

サブテーブルのtableタグのclass属性にはいくつか値が入っています。その中のsubtable-数字が一意にサブテーブルを特定できる値なので、この値を控えておきましょう。

<!-- サブテーブルはこんな感じのtable要素です -->
<table class="subtable-gaia subtable-XXXXXX show-subtable-gaia"></table>

2. レコードの詳細画面表示時のイベントをキャッチする

ここから、kintone JSカスタマイズのコードを書きます。

まず、レコードの詳細画面が表示されたときのイベントをキャッチします。

(() => {

// レコードの詳細画面が表示されたときのイベント
kintone.events.on("app.record.detail.show", (event) => {

});

})();

参考記事

3. サブテーブルのtable要素を取得

1で控えた値を使い、サブテーブルのtable要素を取得します。

kintone.events.on("app.record.detail.show", (event) => {

  const table = document.querySelector('.subtable-XXXXXX');
  if (!table) {
    // 要素が存在しない場合
    // 適宜エラーログを吐くなどしてくださいreturn;
  }

});

4. MutationObserverでtable要素の変更を監視する

table要素は取得できたし、いざ装飾!、といきたいところですが、サブテーブルの各行は詳細画面表示後に非同期で読み込まれるため、詳細画面表示後には行が全くない状態です。

  // このタイミングでは行が無いため、装飾できない
  const table = document.querySelector('.subtable-XXXXXX');

MutationObserverを利用し、table要素内のtbody要素の変更を監視、各行が読み込まれたタイミングで処理を実行できるように設定します。

  const observer = new MutationObserver((mutationList) => {
    for (const mutation of mutationList) {
      if (mutation.type === "childList") {
        // 読み込まれた行のtr要素を取得
	// 配列にしているが、基本は一つずつ呼び出される
        const trs = Array.from(mutation.addedNodes);}
    }
  });
  
  // table要素内のtbody要素の子要素を監視
  observer.observe(table.tBodies[0], {
    childList: true
  });

observer.disconnectは呼んだほうがいい?

レコードの詳細画面はSPAで、次のレコードを表示する時などはブラウザのリロードが発生しません。そのため、「詳細画面を行き来しまくるとMutationObserverが大量にできてしまい、なんかよくなさそうじゃない?🤔」「他のレコードの詳細画面に遷移するときに、observer.disconnectを呼んで監視を止めたほうがよくないか?🤔」と心配になりましたが、調べてみると監視している要素が削除されGCされると、その要素を監視していたMutationObserverも削除されるとのことでした。賢い!

MutationObserver.disconnect() - Web API | MDN

監視されている要素が DOM から削除され、その後ブラウザのガベージコレクション機構によって解放された場合、MutationObserver も同様に削除されます。

ということで、disconnectは呼ばなくても大丈夫です。

5. 好きに装飾しましょう

tr要素が取得できたので、あとは思い思い装飾しましょう。

const trs = Array.from(mutation.addedNodes);

trs.forEach((tr) => {
  // ex) 0列目のセルの背景色を緑にする
  tr.cells[0].style.backgroundColor = 'green';
});

筆者の職場の例だと、なにか対応が必要な行の背景色を赤くして目立たせるなどしています。

以下、コードを全て繋げたもの

(() => {

// レコードの詳細画面が表示されたときのイベント
kintone.events.on("app.record.detail.show", (event) => {
  const table = document.querySelector('.subtable-XXXXXX');
  if (!table) {
    // 要素が存在しない場合
    // 適宜エラーログを吐くなどしてくださいreturn;
  }
  const observer = new MutationObserver((mutationList) => {
    for (const mutation of mutationList) {
      if (mutation.type === "childList") {
        // 読み込まれた行のtr要素を取得
	// 配列にしているが、基本は一つずつ呼び出される
        const trs = Array.from(mutation.addedNodes);
	
	trs.forEach((tr) => {
          // ex) 0列目のセルの背景色を緑にする
          tr.cells[0].style.backgroundColor = 'green';
        });
      }
    }
  });
  
  // table要素内のtbody要素の子要素を監視
  observer.observe(table.tBodies[0], {
    childList: true
  });
});

})();

Discussion