グループフィールドの開閉はResizeObserverやMutationObserverで検知できる。これにより、スペースフィールド内にコンテンツを表示する際の遅延ロードが可能となる。
KintoneのJavaScriptカスタマイズおよびプラグイン開発で、フォームのグループフィールドの開閉を検知する方法をご紹介します。
スペースフィールドを表示先として使う
Kintone APIではスペースのDOM要素を取得できるので、そこに子要素を追加することで画像やWebGLアプリといった色々なコンテンツを動的にロードして表示できます。今回は例として、ランダムに犬の画像のURLを返すWeb APIを呼び出して、スペース内にその画像を表示してみます。以下はJSカスタマイズのソースコードと実行例です。なおエラー処理は簡略化しています。
(function() {
"use strict";
const handleDetailShow = (event) => {
const space = kintone.app.record.getSpaceElement('space1');
if (space != null) {
kintone.proxy(`http://shibe.online/api/shibes?count=1`, 'GET', {}, {})
.then(function(args) {
const shibes = JSON.parse(args[0]);
const imageUrl = shibes[0];
const img = document.createElement('img');
img.src = imageUrl;
img.style.position = 'absolute';
img.style.maxHeight = '100%';
img.style.maxWidth = '100%';
space.appendChild(img);
})
.catch(e => console.error(e));
}
};
// 詳細画面が開いた時のイベント
kintone.events.on('app.record.detail.show', handleDetailShow);
})();
スペースをグループに収納したい
上記例では、レコード内に常に犬が鎮座(または直立)します。普段は隠しておいて、見たい時だけ見られるようにしましょう。スペースをグループフィールドの中に入れて、デフォルトで閉じた状態にします。
無事解決…ではありません。これではレコード画面を開く度、ただちにWeb APIのリクエストと画像のロードが発生してしまいます。画面に表示されないコンテンツをロードするのは無駄なので避けたいところですが、残念ながらKintoneにはグループの開閉を検知するAPIがありません。これについて一応の解決策を見つけましたので、次節で説明します。
グループの開閉を検知する方法
方法1: スペースの表示状態を監視する
ブラウザAPIのResizeObserverを使って、グループに入ったスペースの表示状態の変化を検知する方法です。ResizeObserverはElementの寸法の変更を監視し、変更の発生時にコールバック関数を呼び出します。
スペースフィールドのDOM要素(HTMLElement)はKintone APIのkintone.app.record.getSpaceElement(id)で取得できます。グループフィールドが閉じている状態だとグループのDOM要素のdisplay
プロパティがnone
になるようなので、それをチェックすれば良さそうです。ところがdisplayプロパティは子に継承されないので、スペース要素の同プロパティを見ても画面に表示されているかどうかは判別できません。そこで、HTMLElement.offsetParentプロパティを使います。「要素またはその親要素のdisplayプロパティがnoneに設定されている」状況ではoffsetParent
はnull
を返す仕様なので、スペース要素についてこのプロパティをチェックすればOKですね。
ソースコード例を示します。
(function() {
"use strict";
const handleDetailShow = (event) => {
const space = kintone.app.record.getSpaceElement('space1');
if (space == null) return;
const resolve = (args) => {
const shibes = JSON.parse(args[0]);
const imageUrl = shibes[0];
const img = document.createElement('img');
img.src = imageUrl;
img.style.position = 'absolute';
img.style.maxHeight = '100%';
img.style.maxWidth = '100%';
space.appendChild(img);
};
const reject = (e) => console.error(e);
if (space.offsetParent != null) {
kintone.proxy(`http://shibe.online/api/shibes?count=1`, 'GET', {}, {}).then(resolve).catch(reject);
} else {
const observer = new ResizeObserver((entries) => {
console.debug(space);
if (space.offsetParent != null) {
kintone.proxy(`http://shibe.online/api/shibes?count=1`, 'GET', {}, {}).then(resolve).catch(reject);
observer.disconnect();
}
});
observer.observe(space);
}
};
// 詳細画面が開いた時のイベント
kintone.events.on('app.record.detail.show', handleDetailShow);
})();
※ResizeObserverはInternet Explorer未対応です。
方法2: グループのクラスを監視する
ブラウザAPIのMutationObserverを使って、グループの状態の変化を検知する方法です。方法についてはkintoneカスタマイズフォーラムで説明を下さった方がいらっしゃいますので、以下リンク先をご覧ください。
https://developer.cybozu.io/hc/ja/community/posts/4975839587865/comments/5076372560665
本記事のケースの場合は、スペース要素の親を辿って、control-group-gaia-collapsed
クラスを持つ要素が見つかればそれを監視対象とすればOKです。見つからなければ、グループに入っていないか既にグループが開いているので監視の必要はありません。すぐにデータをロードしてコンテンツを表示しましょう。
まとめ
コンテンツをデフォルトで非表示にしつつ、表示されるタイミングまでリクエストを遅らせる遅延ロードも実装できました。なお上記2つの方法はいずれもDOM要素のプロパティを直接見ているので、Kintoneの変更によって動かなくなる可能性があります。ご注意ください。
記事が面白かった方、参考になった方は、是非「イイね」お願いします👍