kintoneのJavaScriptカスタマイズを見ていると、
たまにこういうコードに出会う。
const inputFiles = document.querySelectorAll('.input-file-cybozu');
const inputFile_1 = inputFiles[0];
最初見たとき、
かなり怖かった。
なぜか。
これは、
「画面上の1番目の添付ファイル欄」
を見ているだけだから。
「今たまたまその順番」なだけ
例えば、
inputFiles[0]
は、
- 今のレイアウト
- 今の表示順
- 今のDOM構造
で、
たまたま最初にいる添付欄。
でも、
業務仕様としては、
「特定の添付ファイルフィールド」
を見たいわけですよね。
だからレイアウト変更で壊れる
例えば、
- フィールド追加
- グループ移動
- 非表示条件変更
- kintone側DOM変更
こういう変更が入る。
すると、
inputFiles[0]
が、
突然別の添付欄を指し始める。
一番怖いのは「エラーにならない」
これ、
本当に怖い。
例えば、
税務顧問を見てるつもり
↓
実際は別ファイルを見てる
↓
でも正常動作して見える
が起きる。
つまり、
“静かに壊れる”
んですよね。
保守で一番危険なタイプ。
じゃあrecordを見ればいいのでは?
最初、
僕もそう思った。
つまり、
record['添付ファイル'].value
を使えばいいのでは、と。
でも実際試すと、
保存前イベントでは取得できないケースがあった。
添付ファイルは普通のフィールドと少し違う
kintoneの添付ファイルって、内部的にはかなり特殊。
新規にアップロードしたファイルは、保存前(submit)イベントの時点ではまだ fileKey が発行されていません。
そのため、保存前イベントで
record['添付ファイル'].value
を見ても、 [](空配列)が返ってくる。
(※すでに保存済みのファイルは取得できますが、新しく入れたものは取れない)
つまり、
- DOMには表示されてる
- でもrecordにはまだ反映されてない
が起きる。
普通のフォーム感覚で触ると、
かなりハマる。
だから昔の実装意図も分かる
ここで、
「あぁ、だからDOM見たのか」
と理解した。
つまり、
保存前に添付有無をチェックしたい
↓
でもrecordでは取れない
↓
DOMを見るしかない
という流れ。
なので、
DOMを触ったこと自体
は、
当時としては合理性がある。
でも問題は「index依存」
ただし、
問題はそこじゃない。
本当に危険なのは、
querySelectorAll(...)[0]
のほう。
つまり、
“画面上の何番目か”
を業務仕様にしてしまっていること。
どうしてもDOMを見るなら「順番」ではなく「業務項目」で取る
もちろん、
添付ファイルのように、
保存前ではrecordに反映されない
ケースでは、
DOMを見るしかない場面もある。
なので、
DOMを使うこと自体
は、
必ずしも悪ではない。
ただし、
それでも避けたいのが、
querySelectorAll(...)[0]
のような、
“何番目か”依存。
もしDOMを使うなら、
- class構造
- ラベル文字列
を使って、
「添付ファイルという業務項目」
を特定して取得したい。
少なくともこれなら、
- フィールド追加
- レイアウト変更
- グループ移動
だけで、
突然別項目を見る事故はかなり減らせる。
保存後なら普通に取れる
保存後イベント、
app.record.create.submit.successapp.record.edit.submit.success
でなら、
record['添付ファイル'].value
が普通に取れる。
つまり、
- contentType
- size
- fileKey
も取得できる。
じゃあ「保存後に検査」で良いのでは?
ここで発想を変えた。
無理やり保存前で止めなくても、
「保存後に確実に検査」
すれば良いのでは?
と。
実務では「完全ブロック」が正義とは限らない
エンジニアって、
「保存前に絶対止めるべき」
と思いがち。
でも現場って、
- とりあえず保存したい
- 後で修正したい
- 一時保存したい
も普通にある。
だから、
保存は許可
↓
業務進行を止める
という設計も、
かなり実務的。
アプローチA:プロセス管理のボタンを押した時にチェックする
もしアプリで「プロセス管理(ワークフロー)」を使っているなら、これもスマート。
ステータス変更時イベント(app.record.detail.process.proceed)を使う。
この時点ではレコードが保存されているので、添付ファイルの情報は確実に取得できる。
kintone.events.on('app.record.detail.process.proceed', (event) => {
const record = event.record;
// 「作業完了」にステータスを進めるときだけチェック
if (event.nextStatus.value === '作業完了') {
const files = record['添付ファイル'].value;
if (files.length === 0) {
// エラーメッセージをセットすると、
// kintoneがステータス変更を自動でブロックする
event.error =
'【エラー】作業完了にするには、成果物のファイルを添付してください。';
}
}
return event;
});
これなら、書きかけの「一時保存」は邪魔しない。
いざ、
「次のステップへ回そう!」
とボタンを押したタイミングで、
確実に不備を弾くことができる。
業務の柔軟性を奪わない、
とてもkintoneらしい制御。
アプローチB:保存後にチェックし、画面上に警告を出す
保存後イベントで、
- PDFかチェック
- サイズチェック
- 添付必須チェック
を行う。
もし不備があれば、
添付ファイルに不備があります。
PDFのみ、10MB以内で添付してください。
を表示。
さらに、詳細画面に
- プロセス管理ボタンを非表示
- 「添付ファイルを修正してください」を表示
にする。
つまり、
保存はできる
でも次の業務には進めない
という制御。
こっちのほうがkintone向き
kintoneって、
- 現場運用で育つ
- レイアウト変更が多い
- 非同期処理が多い
- 一時保存文化がある
ので、
「保存前に全部止める」
より、
「業務フローで制御する」
ほうが、
結果的に安全なことがある。
最後に
今回、
最初は
「DOMを見るな」
と思っていた。
でも実際に調べると、
「保存前では添付情報が不安定」
という、
kintone側事情も見えてきた。
だから今回の本質は、
「DOMを使うな」
ではない。
“画面上の何番目か”
を業務仕様にするな
なんですよね。
そして場合によっては、
「保存前で無理に止める」
より、
「保存後に確実に検査し、業務フロー側で進行を制御する」
ほうが、
ずっと安全だったりする。
