ラジオボタンを利用してレコード内集計する

目次

はじめに

kintone の「計算」フィールドは、フィールドの値の自動計算に利用できてとても便利です。
でも、こんなことで困った経験はありませんか?

  • 分析のために、レコード内数値の合計や平均を表示したい。
  • ユーザーの入力を簡易化させるために、数値入力ではなくラジオボタン等の選択肢から選ばせたい。

こういった場合も、2020 年 1 月のアップデートで、 IF 関数 (External link) を使って実現できるようになりました。

IF 関数でも実現できますが、今回はカスタマイズで、ラジオボタンやドロップダウン等、選択した値の自動計算を実現する方法を紹介します!

実現できること

ラジオボタン等で選択されている数値の合計または平均を算出し、指定したフィールドに表示します。
計算対象として利用できるのは次のフィールドです。

  • ラジオボタン
  • チェックボックス
  • 複数選択
  • ドロップダウン

さらに、追加の機能です。
レコード内で選択した値の数をそれぞれカウントし、指定したフィールドに表示します。

さまざまなアプリでの活用が期待できるので、対象フィールドを JavaScript のコードに直接書くのではなく、メンテナンスしやすいように設定画面で設定できるようにすると便利ですね。
このため、今回はプラグインという形で実現することにしました。

設定画面のイメージ

集計対象フィールドや集計方法を、設定画面で設定できます。これなら、JavaScript の知識がない人でも手軽にメンテナンスできますね!

サンプルコード

サンプルコードは、GitHub に公開されています。

https://github.com/kintone-samples/SAMPLE-select-type-form-totalization (External link)

プラグインとして利用してみたい方は GitHub (External link) からソースコードをダウンロードし、 plugin-packer を参考にパッケージングを行ってください。

カスタマイズのポイント

ここでは、プラグインで実装されているカスタマイズ( totalization.js (External link) )のポイントについて解説します!

集計

集計(値の数、合計、平均)の処理は、calcCount、calcSum、calcAverage という function でそれぞれ行っています。

ポイント1:フィールド値の複数選択への対応

集計対象フィールドには複数選択可能なフィールドタイプ(チェックボックス、複数選択)が含まれるため、$.isArray で配列かを判断して処理を分けています。

46
47
48
49
50
51
52
53
if (!$.isArray(record[field].value)) {
    var val = record[field].value;
    count += (val === word);
} else {
    $.each(record[field].value, function(j, value) {
        count += (value === word);
    });
}
ポイント2:テーブル内フィールドへの対応

テーブル内のフィールドはフィールド値の階層が異なるため、通常のフィールドとは別の対応が必要です。
詳細は、 フィールド形式 の「テーブル」を参照してください。

テーブル内フィールドを取得するため、テーブルの中の階層に入っているフィールドに対して$.each で処理を行います。

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
$.each(subTableCodes, function(i, subTableCode) {
    var subRecords = record[subTableCode].value;
    $.each(subRecords, function(j, subRecord) {
        var subRecordFields = subRecord.value;
        $.each(subRecordFields, function(subRecordFieldCode, subRecordField) {
            if (targetFields.indexOf(subRecordFieldCode) !== -1) {
                switch (method) {
                    case 'sum' :
                        sum = formatSum(sum, calcSum(subRecordFields, subRecordFieldCode));
                        break;
                    case 'average' :
                        var avg = calcAverage(subRecordFields, subRecordFieldCode);
                        sum = sum + avg.sum;
                        countAvg = countAvg + avg.countAvg;
                        break;
                    case 'count' :
                        count = count + calcCount(subRecordFields, subRecordFieldCode, word);
                        break;
                    default:
                        break;
                }
            }
        });
    });
});

なお、テーブルのフィールドコードは事前にまとめて取得しています。

10
11
12
13
14
15
16
17
18
function getSubTableCodes(record) {
    var codes = [];
    $.each(record, function(recordFieldCode, recordField) {
        if (recordField.type === 'SUBTABLE') {
            codes.push(recordFieldCode);
        }
    });
    return codes;
}

イベント処理

集計処理が動くタイミングも重要です。

レコードの編集・保存時はもちろんですが、入力中も集計値は自動更新してほしいですよね。
そんなときは、各画面のフィールド値変更イベントを利用します。

ポイント:フィールド値変更イベントの利用

対象フィールドからトリガーにしたいフィールドイベントをすべて生成し、すべてのイベントに対して events.on で処理が動くようにしています。
また、モバイルでも動くようにモバイル用イベントも対象としています。

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
function bindFieldEvents(caculations) {
    var fieldEvents = [];
    $.each(caculations, function(i, caculation) {
        $.each(caculation.targetFields, function(j, targetField) {
            fieldEvents.push('app.record.index.edit.change.' + targetField);
            fieldEvents.push('app.record.edit.change.' + targetField);
            fieldEvents.push('app.record.create.change.' + targetField);
            fieldEvents.push('mobile.app.record.index.edit.change.' + targetField);
            fieldEvents.push('mobile.app.record.edit.change.' + targetField);
            fieldEvents.push('mobile.app.record.create.change.' + targetField);
        });
    });

    fieldEvents = uniqueEvents(fieldEvents);
    kintone.events.on(fieldEvents, function(fieldEvent) {
        calculator(caculations, fieldEvent['record']);
        return fieldEvent;
    });
}

テーブル内フィールドが対象に含まれる場合、テーブルの行追加・行削除時にも再計算が必要となるため、テーブル自体のフィールド値変更イベントにも対応しています。

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
function bindSubTableEvents(caculations) {
    var subTableEvents = [];
    $.each(subTableCodes, function(i, tableCode) {
        subTableEvents.push('app.record.edit.change.' + tableCode);
        subTableEvents.push('app.record.create.change.' + tableCode);
        subTableEvents.push('mobile.app.record.edit.change.' + tableCode);
        subTableEvents.push('mobile.app.record.create.change.' + tableCode);
    });

    subTableEvents = uniqueEvents(subTableEvents);
    kintone.events.on(subTableEvents, function(subTableEvent) {
        calculator(caculations, subTableEvent['record']);
        return subTableEvent;
    });
}

注意事項

  • 本カスタマイズについて、プラグインファイル(zip ファイル)の公開予定はありません。
    プラグインとして利用してみたい方は、 サンプルコード を確認しパッケージングを行ってください。
  • プラグインの詳しい使い方は、GitHub の README (External link) を確認してください。
  • 本カスタマイズのデモ環境はご用意しておりません。
information

この Tips は、2021 年 1 月版 kintone で動作を確認しています。