【kintoneカスタマイズ】テーブルが変更されたらデータを日付順に並べ替える
前回の記事の発展で「測定履歴を測定日順に並び替える」という思いつきを書いたんですが、実際に挑戦してみました。これ、意外と強敵ですw
妥当なやり方とはとても思えないのですが、とりあえず、自分の知識内でのやりかたです。
どんなカスタマイズをするのか?
「新規にレコードを記入するとき」「既存のデータを編集するとき」に「測定履歴の情報が追加・修正された」ことをトリガーに測定履歴を測定日の昇順に並び替える。
気をつけないといけないこと
「測定履歴」はテーブルですが、テーブルのchangeイベントは、
なんです。つまり、テーブル内の各フィールドの変更を察知するには、「測定履歴」ではなく、テーブルの中の各フィールドを指定する必要があります。
kintone.events.on(
[
'app.record.create.change.測定日',
'app.record.edit.change.測定日',
'app.record.create.change.体温',
'app.record.edit.change.体温',
'app.record.create.change.SpO2',
'app.record.edit.change.SpO2',
],
前回のこれですね。
さて、テーブルの中を並び替えるということはどういうことか?言い換えれば、「テーブルの中身の各行のフィールドの値を変更する」ということになります。
あれ?このカスタマイズのトリガーって「測定履歴の情報が追加・修正された」ときに発火するんじゃなかったっけ?そうなんです。return eventで反映された瞬間、変更部分の数だけ発火が積まれることになりますw
もうこの時点でこのやり方は無理筋っぽい……素直に、ボタンを設置するなり、保存時に並び替えるなりすればいいんじゃない?って思うんですが、敢えて強行突破してみました。
作ったコード
こんな感じです。
あ、前回のコードを流用して、更に一つのファイルに纏めました。
(() => {
('use strict');
// フィールドを編集不可にする
kintone.events.on(['app.record.create.show', 'app.record.edit.show', 'app.record.index.edit.show'], (event) => {
const items = ['測定日_最新', '体温_最新', 'SpO2_最新'];
const record = event.record;
items.forEach((item) => (record[item].disabled = true));
return event;
});
// 最後尾のデータを最新情報としてコピーする
kintone.events.on(
[
'app.record.create.change.測定日',
'app.record.edit.change.測定日',
'app.record.create.change.体温',
'app.record.edit.change.体温',
'app.record.create.change.SpO2',
'app.record.edit.change.SpO2',
],
function (event) {
const record = event.record;
const table = record['測定履歴'].value;
const sortedTable = Array.from(table).sort((a, b) => {
if ((!!a.value.測定日.value ? a.value.測定日.value : '1900-01-01') > (!!b.value.測定日.value ? b.value.測定日.value : '1900-01-01')) {
return 1;
} else {
return -1;
}
});
if (JSON.stringify(table.map((obj) => obj.value.測定日)) != JSON.stringify(sortedTable.map((obj) => obj.value.測定日))) {
record['測定履歴'].value = sortedTable;
}
const targetRow = sortedTable[sortedTable.length - 1].value;
record.測定日_最新.value = targetRow.測定日.value;
record.体温_最新.value = targetRow.体温.value;
record.SpO2_最新.value = targetRow.SpO2.value;
return event;
},
);
})();
ポイントの説明
データのソート
const record = event.record;
const table = record['測定履歴'].value;
const sortedTable = Array.from(table).sort((a, b) => {
if ((!!a.value.測定日.value ? a.value.測定日.value : '1900-01-01') > (!!b.value.測定日.value ? b.value.測定日.value : '1900-01-01')) {
return 1;
} else {
return -1;
}
});
「測定履歴」の並び替えですが、「一度配列に落とし込んで、並び替えた後に、ごっそり配列の内容で置き換える」という手法をとることにしました。
測定日の並び替えにあたっては、nullの場合に比較がうまくいかないので、三項演算子を使ってnullは'1900-01-01'に置き換えて並び替えを行っています(実際にフィールドに代入されるわけではなく、ソートのためだけに置き換えています)。
「測定履歴」の内容の差し替え
if (JSON.stringify(table.map((obj) => obj.value.測定日)) != JSON.stringify(sortedTable.map((obj) => obj.value.測定日))) {
record['測定履歴'].value = sortedTable;
}
置き換えるだけではなく、敢えてif文で囲っています。何をしているかというと、「測定日の並び替えが実際にあった場合のみ、測定履歴を差し替える」という内容です。
なぜこんなことをするかというと、差し替えを行うと、それによって「修正されたフィールドの個数分のchangeイベントが発生」するからです。もし、このif文がないと、
発生したイベントでも無条件に測定履歴を更新
修正されたフィールドの個数分のchangeイベントが発生
以下ねずみ算……
で、最終的にエラーで止まってしまいます。
ですので、このif文を使うことによって、無駄なchangeイベントの発生を1世代のみで止めている感じです。つまり、見た目上は一瞬でも、少なくとも1世代分の同じような処理が発生しているわけで、すごく消極的で泥臭い解決方法となっています。
測定日が並べ変わったかの確認
JSON.stringify(table.map((obj) => obj.value.測定日))
並びを確認するには配列を順番に比較する方法もありますが、今回はJSON.stringifyを使って文字列に変換して比較する形をとってみました。個人的にはコードとして趣旨が分かりやすい気がしますが、どうなんだろう?