はじめに
以前、kintoneのJavaScriptカスタマイズを保守していたとき、
こんな実装を見かけた。
element.parentNode.parentNode.parentNode.style.display = 'none';
最初は、
「なぜこんな深く親要素をたどっているんだろう?」
と思った。
ただ、画面構成を見ていくと、
当時こうした実装になった理由も見えてきた。
今回は、
- なぜ親要素を消す実装になっていたのか
- どこが危険なのか
- 今ならどう実装するべきか
をまとめたい。
当時の画面構成
当時のkintone画面では、
- スペースフィールド(要素ID付き)
- その横にラベル
- さらに横にフィールド
という構成になっていた。
イメージとしてはこんな感じ。
[SPACE_A] [ラベル] [フィールド]
そして、
表示・非表示を切り替えたい対象は、
- ラベル
- フィールド
を含めた「行全体」だった。
なぜ親要素を消していたのか
理由として大きかったのが、
当時はラベル要素に要素IDを付与できなかった
こと。
つまり、
kintone.app.record.setFieldShown()
でフィールドは消せても、
ラベル側を直接制御できなかった。
すると、
- ラベルだけ残る
- 空白が崩れる
- 横並びレイアウトが不自然になる
という問題が起きる。
そのため、
「行ごと消す」
という発想になったのだと思う。
そして、その手段として採用されていたのが、
parentNode.parentNode.parentNode
で親要素をさかのぼって消す方法だった。
実際のイメージ
例えばこんなコード。
const space = kintone.app.record.getSpaceElement('SPACE_A');
if (space) {
const row = space.parentNode.parentNode.parentNode;
row.style.display = 'none';
}
スペースフィールドを起点にして、
その行全体を非表示にしている。
当時としては、
「ラベル込みで綺麗に消したい」
という意図だったのだと思う。
ただ、この実装には問題がある
問題は、
DOM構造に依存している
こと。
例えば、
parentNode.parentNode.parentNode
というコードは、
「今のkintoneのHTML構造」
を前提にしている。
つまり、
- Cybozu側のアップデート
- DOM構造変更
- 他JSとの競合
によって簡単に壊れる可能性がある。
保守時につらいポイント
特に大変なのが、
「何をしたいコードなのか分かりづらい」
こと。
本来やりたいのは、
「この行を非表示にしたい」
なのに、
コード上は、
3つ上のdivを消す
になっている。
つまり、
意味ではなく構造に依存している。
これが保守をかなり難しくする。
現在は状況が変わっている
今のkintoneでは、
ラベル要素にも要素IDを付与できる
ようになっている。
つまり、
以前のように
「ラベルを消せないから親ごと消す」
必要性がかなり減った。
今ならどう実装するべきか
現在なら、
kintone標準APIで非表示制御する
のが基本になる。
例えば、
kintone.app.record.setFieldShown('fieldCode', false);
を使い、
必要に応じて、
- ラベル
- スペース
- 関連要素
も個別に制御する。
これなら、
- DOM構造に依存しない
- アップデート耐性が高い
- 保守しやすい
- 意図が分かりやすい
というメリットがある。
「当時は仕方なかった」もある
今回のコードは、
単純に「悪い実装だった」というより、
当時のkintone仕様上、そうせざるを得なかった
部分もあると思う。
ただ、
現在はkintone側の機能も増えている。
だからこそ、
昔のDOM依存実装をそのまま使い続けるのではなく、
「今のkintoneで正しい実装に置き換えられないか」
を見直すことも大切だと思う。
最後に
kintoneカスタマイズは自由度が高い。
だからこそ、
「動く」だけではなく、
- 保守性
- アップデート耐性
- 意図の分かりやすさ
もかなり重要になる。
特にDOM直操作は、
短期的には便利でも、
長期運用では負債になりやすい。
昔の実装を見ると、
「当時の制約」と「今のベストプラクティス」
の違いがよく分かって面白い。