第 16 回 kintone JavaScript カスタマイズのプログラム実例を学ぼう④(テーブル操作)

著者名: 村濱一樹 (External link) (kintone エバンジェリスト)

目次

information

JavaScript 初心者がカスタマイズに必須の知識をより学べるよう、チュートリアルの内容を充実させてリニューアルしました。
リニューアル後のチュートリアルは次のページを参照してください。
はじめよう JavaScript

題材

今回は kintone における テーブル操作の基本(行の追加・更新・削除) のサンプルプログラムからテーブル内のチェックボックスフィールドを省いた簡易的なアプリを用意しましたのでそれをつかって学んでいきましょう。
テーブルは非常に便利な機能ですので、JavaScript カスタマイズもできるようになるともっとやれることの幅が広がります。

サンプル記事と少し重複している内容もあると思いますがより細かく説明します。

アプリの準備

フィールド名 フィールドタイプ フィールドコード 補足
追加_テキスト 文字列(1行) 追加_テキスト
追加_チェックボックス チェックボックス 追加_チェックボックス 項目名は次のとおり
  • チェック1
  • チェック2
- スペース - 要素 ID に「addSpace」を入力
更新_行番号 数値 更新_行番号
更新_テキスト 文字列(1行) 更新_テキスト
更新_チェックボックス チェックボックス 更新_チェックボックス 項目名は次のとおり
  • チェック1
  • チェック2
- スペース - 要素 ID に「updateSpace」を入力
削除_行番号 数値 削除_行番号
- スペース - 要素 ID に「deleteSpace」を入力
テーブル テーブル テーブル

テーブル内のフィールドは以下のとおりです。

フィールド名 フィールドタイプ フィールドコード 補足
行番号 数値 行番号
テキスト 文字列(1行) テキスト

テーブルについて

テーブルの機能自体については次のページ等を参考にしてください。

テーブルを JavaScript カスタマイズするには

  1. テーブルデータの取得
    通常のフィールドのように kintone.events.on() を使って、「詳細画面が表示されたとき」のイベントでテーブルのフィールドのデータを取得できます。
    イベントの定義方法などは第 13 回と第 14 回を振り返ってみましょう。
  2. テーブルデータの参照・編集
    データを取得したら、データを編集してテーブルフィールドに反映させることができます。
    テーブルは構造が少し複雑で、次のようになっています。
    API 自体の詳細は はじめよう kintone API〜第 6 回 テーブルの値を利用する(条件付きでデータを集計) を参考にしてください。
    この記事では API 自体の解説ではなくプログラムを中心に解説します。

テーブルを取得した際のデータは次の構造になっています。
フィールドタイプは「SUBTABLE」です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
"<フィールドコード>": {
    "type": "SUBTABLE",
    "value": [
        {
            "id": "48290",
            "value": {
                "文字列_1行_0": {
                    "type": "SINGLE_LINE_TEXT",
                    "value": "サンプル1"
                },
                "数値_0": {
                    "type": "NUMBER",
                    "value": "1"
                },
                "チェックボックス_0": {
                    "type": "CHECK_BOX",
                    "value": [
                        "選択肢1"
                    ]
                }
            }
        },
        {
             "id": "48291",
             "value": {
                 "文字列_1行_0": {
                     "type": "SINGLE_LINE_TEXT",
                     "value": "サンプル2"
                 },
                 "数値_0": {
                     "type": "NUMBER",
                     "value": "2"
                 },
                 "チェックボックス_0": {
                     "type": "CHECK_BOX",
                     "value": [
                         "選択肢2"
                     ]
                 }
             }
        }
    ]
}

プログラム

プログラムは下記です。
少しずつピックアップして、内容を解説していきます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/*
 * kintone table sample program
 * Copyright (c) 2022 Cybozu
 *
 * Licensed under the MIT License
*/

(() => {
  'use strict';
  kintone.events.on(['app.record.create.show', 'app.record.edit.show'], (e) => {

    // 追加ボタンを設置
    const addSpace = kintone.app.record.getSpaceElement('addSpace');
    const addButton = document.createElement('button');
    addButton.innerHTML = '追加';
    addButton.onclick = addRow;
    addSpace.appendChild(addButton);

    // 更新ボタンを設置
    const updateSpace = kintone.app.record.getSpaceElement('updateSpace');
    const updateButton = document.createElement('button');
    updateButton.innerHTML = '更新';
    updateButton.onclick = updateRow;
    updateSpace.appendChild(updateButton);

    // 削除ボタンを設置
    const deleteSpace = kintone.app.record.getSpaceElement('deleteSpace');
    const deleteButton = document.createElement('button');
    deleteButton.innerHTML = '削除';
    deleteButton.onclick = deleteRow;
    deleteSpace.appendChild(deleteButton);
  });

  // 行を追加する関数
  const addRow = () => {
    const record = kintone.app.record.get().record;
    const addText = record.追加_テキスト.value;
    record.テーブル.value.push({
      value: {
        行番号: {
          value: '',
          type: 'NUMBER',
        },
        テキスト: {
          value: addText,
          type: 'SINGLE_LINE_TEXT',
        }
      }
    });
    resetRowNo(record);
    kintone.app.record.set({record: record});
  };

  // 行を更新する関数
  const updateRow = () => {
    const record = kintone.app.record.get().record;
    const updateText = record.更新_テキスト.value;
    const targetRowNo = record.更新_行番号.value;
    record.テーブル.value.forEach((row) => {
      if (row.value.行番号.value === targetRowNo) {
        row.value.テキスト.value = updateText;
      }
    });
    resetRowNo(record);
    kintone.app.record.set({record: record});
  };

  // 行を削除する関数
  const deleteRow = () => {
    const record = kintone.app.record.get().record;
    const targetRowNo = record.削除_行番号.value;
    record.テーブル.value.forEach((row, i) => {
      if (row.value.行番号.value === targetRowNo) {
        record.テーブル.value.splice(i, 1);
      }
    });
    resetRowNo(record);
    kintone.app.record.set({record: record});
  };

  // 行番号を更新する関数
  const resetRowNo = (record) => {
    record.テーブル.value.forEach((row, i) => {
      row.value.行番号.value = i + 1;
    });
  };
})();

全体の構成

この JavaScript カスタマイズは、大まかに分けると「スペースフィールドにボタンを設置する」部分と「テーブルの行追加・更新・削除」部分に分かれます。
以降、次のように分割して説明していきます。

スペースフィールドにボタンを設置する処理

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 追加ボタンを設置
const addSpace = kintone.app.record.getSpaceElement('addSpace');
const addButton = document.createElement('button');
addButton.innerHTML = '追加';
addButton.onclick = addRow;
addSpace.appendChild(addButton);

// 更新ボタンを設置
const updateSpace = kintone.app.record.getSpaceElement('updateSpace');
const updateButton = document.createElement('button');
updateButton.innerHTML = '更新';
updateButton.onclick = updateRow;
updateSpace.appendChild(updateButton);

// 削除ボタンを設置
const deleteSpace = kintone.app.record.getSpaceElement('deleteSpace');
const deleteButton = document.createElement('button');
deleteButton.innerHTML = '削除';
deleteButton.onclick = deleteRow;
deleteSpace.appendChild(deleteButton);

テーブルの行を追加する処理

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 行を追加する関数
const addRow = () => {
  const record = kintone.app.record.get().record;
  const addText = record.追加_テキスト.value;
  record.テーブル.value.push({
    value: {
      行番号: {
        value: '',
        type: 'NUMBER',
      },
      テキスト: {
        value: addText,
        type: 'SINGLE_LINE_TEXT',
      }
    }
  });
  resetRowNo(record);
  kintone.app.record.set({record: record});
};

テーブルの行を更新する処理

54
55
56
57
58
59
60
61
62
63
64
65
66
// 行を更新する関数
const updateRow = () => {
  const record = kintone.app.record.get().record;
  const updateText = record.更新_テキスト.value;
  const targetRowNo = record.更新_行番号.value;
  record.テーブル.value.forEach((row) => {
    if (row.value.行番号.value === targetRowNo) {
      row.value.テキスト.value = updateText;
    }
  });
  resetRowNo(record);
  kintone.app.record.set({record: record});
};

テーブルの行を削除する処理

68
69
70
71
72
73
74
75
76
77
78
79
// 行を削除する関数
const deleteRow = () => {
  const record = kintone.app.record.get().record;
  const targetRowNo = record.削除_行番号.value;
  record.テーブル.value.forEach((row, i) => {
    if (row.value.行番号.value === targetRowNo) {
      record.テーブル.value.splice(i, 1);
    }
  });
  resetRowNo(record);
  kintone.app.record.set({record: record});
};

テーブルの行番号を更新する処理

81
82
83
84
85
86
// 行番号を更新する関数
const resetRowNo = (record) => {
  record.テーブル.value.forEach((row, i) => {
    row.value.行番号.value = i + 1;
  });
};

イベントの説明

このサンプルコードでは次のように ['app.record.create.show', 'app.record.edit.show'] とイベントが指定されています。
そのため「レコード追加画面が表示された後」「レコード編集画面が表示された後」にプログラムが動作します。

1
2
kintone.events.on(['app.record.create.show', 'app.record.edit.show'], (e) => { // 以降省略
});

スペースフィールドへボタン設置の説明

はじめよう kintone API 第3回 レコード詳細にもボタンを設置しよう! にも説明がありますが、ボタンを設置する方法について解説します。

今回のサンプルアプリのようにフォーム内にボタンを設置する手順は次のとおりです。
手順 1 は kintone フォーム設定画面で設定し、手順 2〜4 は JavaScript カスタマイズで実施します。

  1. 任意の場所にスペースフィールドを設置し、[要素 ID]を指定する。
    スペースフィールドはデフォルトで[要素 ID]が空欄なので注意してください。
  2. kintone.app.record.getSpaceElement('要素 ID') を使ってスペースフィールドの要素を取得する。
  3. ボタン要素を作成する。
  4. 取得したスペースフィールドに対して appendChild() を使い、作成したボタン要素を挿入する。

下記部分は追加ボタンを設置するためのコードです。

13
14
15
16
17
const addSpace = kintone.app.record.getSpaceElement('addSpace');
const addButton = document.createElement('button');
addButton.innerHTML = '追加';
addButton.onclick = addRow;
addSpace.appendChild(addButton);

スペースフィールドの要素を取得します。

13
const addSpace = kintone.app.record.getSpaceElement('addSpace');

ボタン要素は document.createElement('button') で作成します。

14
const addButton = document.createElement('button');

innerHTML でボタンのテキストを指定し、onclick でボタン押下時に呼び出す関数を指定します。

15
16
addButton.innerHTML = '追加';
addButton.onclick = addRow;

スペースフィールドにボタン要素を挿入します。

17
addSpace.appendChild(addButton);

テーブルフィールドの操作

テーブルの構造について

ここから先はテーブル操作について詳細を説明します。

前提として、テーブルフィールドのデータは、配列で表現されています。
配列の中にさらにオブジェクトが入っており、その中にテーブルの中のフィールド情報や value が入っています。

テーブルのデータの配列とオブジェクト、その扱い方の例

第 12 回 kintone JavaScript カスタマイズで kintone のデータを見てみる で配列とオブジェクトについて触れていますが、テーブルも配列とオブジェクトで構成されています。
実際にデータを取り出したり、変更したりするには次のようにします。

たとえば次の構造のテーブルだった場合のデータの取り出し方を見てみましょう。

例 1:1 行目の[テキスト]フィールドの値を取り出す

コードは次のようになります。
値までたどり着くまでに少し長いので解説します。

1
2
3
4
5
6
7
8
9
const record = kintone.app.record.get().record; // レコードを取得

const tableValue = record.テーブル.value; // テーブルフィールド自体の値を取得
const row = tableValue[0]; // テーブルの1行目を取得
const text = row.value.テキスト.value; // 1行目の中にあるテキストを取得する
console.log(text); // テキスト1 と表示される

// もちろんこのようにつなげてもOK
console.log(record.テーブル.value[0].value.テキスト.value);

まず、kintone.app.record.get().record で現在開いている画面のレコードを取得し、定数 record に格納します。

1
const record = kintone.app.record.get().record; // レコードを取得

record.(ドット)つなぎでテーブルのフィールドコードを指定し、tableValue にテーブル自体のデータを格納します。

3
const tableValue = record.テーブル.value; // テーブルフィールド自体の値を取得

先述の図に照らし合わせてみると、record.テーブル.value の中身は配列です。
1 行目を取得する場合は、次のように [0] と指定します。
2 行目なら [1]、3 行目なら [2] のように、0 からスタートすることを覚えておいてください。

4
const row = tableValue[0]; // テーブルの1行目を取得

最後に、[テキスト]フィールドの値を取得します。
先述の図と照らし合わせながら .value までドットを使ってつなげることでフィールドの値を取得できます。

5
const text = row.value.テキスト.value; // 1行目の中にあるテキストを取得する
例 2:2 行目の[テキスト]フィールドの値を変更する

要領としては例 1 と似ています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const record = kintone.app.record.get().record; // レコードを取得

const tableValue = record.テーブル.value; // テーブルフィールド自体の値を取得
const row = tableValue[1]; // テーブルの2行目を取得
row.value.テキスト.value = '書き換えました'; // 2行目の中にあるテキストを書き換える

// レコードをセットする
kintone.app.record.set({record: record});

// もちろんこのようにつなげてもOK
record.テーブル.value[1].value.テキスト.value = '書き換えました';
kintone.app.record.set({record: record});

row.value.テキスト.value に、あらためて値を代入し、最後に kintone.app.record.set() をすることで書き換えることができます。

例 3:3 行目を追加、追加するものは[行番号]: 3, [テキスト]: テキスト3とする

「行を追加する」ということは、JavaScript 上では「配列を追加する」ということになります。
.push() という関数で配列の要素を追加できます。
Array.prototype.push() (External link)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
const record = kintone.app.record.get().record; // レコードを取得

const tableValue = record.テーブル.value; // テーブルフィールド自体の値を取得

// .push()は、配列に対して行うことができる。1 行分のデータを追加。
tableValue.push({
  value: {
    行番号: {
      type: 'NUMBER', // typeも指定すること
      value: '3'
    },
    テキスト: {
      type: 'SINGLE_LINE_TEXT', // typeも指定すること
      value: 'テキスト3'
    }
  }
});

// レコードをセットする
kintone.app.record.set({record: record});

.push を使い、上記のように 1 行分のオブジェクトを追加させます。
このとき、Type も指定しないと kintone でエラーが出てしまいますので注意してください。

例 4:2 行目を削除する

.splice() という関数で行(配列の要素)を削除します。
Array.prototype.splice() (External link)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const record = kintone.app.record.get().record; // レコードを取得

const tableValue = record.テーブル.value; // テーブルフィールド自体の値を取得

// .splice()で2行目を削除
// .splice([削除したい行], [いくつ削除するか(今回は1行)])  と指定する
tableValue.splice(1, 1);

// レコードをセットする
kintone.app.record.set({record: record});

テーブルの行を追加する処理

下記は行を追加する関数です。

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 行を追加する関数
const addRow = () => {
  const record = kintone.app.record.get().record;
  const addText = record.追加_テキスト.value;
  record.テーブル.value.push({
    value: {
      行番号: {
        value: '',
        type: 'NUMBER',
      },
      テキスト: {
        value: addText,
        type: 'SINGLE_LINE_TEXT',
      }
    }
  });
  resetRowNo(record);
  kintone.app.record.set({record: record});
};

テーブルの 1 行 1 行は配列の要素なので、行を追加するには、配列へ要素を追加することになります。
配列に対し、.push() を使うことで要素の追加ができます。

kintone.app.record.get().record で、現在開いている画面のレコードを取得します。

36
const record = kintone.app.record.get().record;

入力された文字列を取得し、addText に格納します。

37
const addText = record.追加_テキスト.value;

record.テーブル.value に、新しい行を .push() します。
テーブルに必要な[行番号]フィールドと[テキスト]フィールドの情報を渡しています。

38
39
40
41
42
43
44
45
46
47
48
49
record.テーブル.value.push({
  value: {
    行番号: {
      value: '',
      type: 'NUMBER',
    },
    テキスト: {
      value: addText,
      type: 'SINGLE_LINE_TEXT',
    }
  }
});

後述の「行番号を更新する関数」で行番号を更新します。

50
resetRowNo(record);

ここまでの変更点を kintone に反映させます。

51
kintone.app.record.set({record: record});

また、サンプルでは関数を定義して使っています。
関数の定義についてはじめよう JavaScript第 9 回 JavaScriptの基本機能 関数を使う その 1 で解説しています。

テーブルの行を更新する処理

下記は行を更新する関数です。
行を追加する処理と同様、同じ要領で関数に行を更新する処理を定義します。

54
55
56
57
58
59
60
61
62
63
64
65
66
// 行を更新する関数
const updateRow = () => {
  const record = kintone.app.record.get().record;
  const updateText = record.更新_テキスト.value;
  const targetRowNo = record.更新_行番号.value;
  record.テーブル.value.forEach((row) => {
    if (row.value.行番号.value === targetRowNo) {
      row.value.テキスト.value = updateText;
    }
  });
  resetRowNo(record);
  kintone.app.record.set({record: record});
};

入力された文字列と行番号を取得し、targetRowNo に格納します。

58
const targetRowNo = record.更新_行番号.value;

forEach() を利用して、テーブルの行数分ループ処理します。
ループ中、指定された行番号と同じ行のときだけ[テキスト]フィールドの値を変更します。

59
60
61
62
63
record.テーブル.value.forEach((row) => {
  if (row.value.行番号.value === targetRowNo) {
    row.value.テキスト.value = updateText;
  }
});

このサンプルではループ処理(繰り返し処理)に forEach() というものを使っています。
for とはちがい、何回繰り返すのか、を指定せずとも行数があるだけ繰り返されるので便利です。
forEach() については forEach, map, filter などをつかって kintone の records 配列をもっと上手に扱う (External link) でも使い方を解説しています。

テーブルの行を削除する処理

下記は行を削除する関数です。
行を更新する処理と同様に、forEach() でループし、該当の行は削除するという流れになっています。

68
69
70
71
72
73
74
75
76
77
78
79
// 行を削除する関数
const deleteRow = () => {
  const record = kintone.app.record.get().record;
  const targetRowNo = record.削除_行番号.value;
  record.テーブル.value.forEach((row, i) => {
    if (row.value.行番号.value === targetRowNo) {
      record.テーブル.value.splice(i, 1);
    }
  });
  resetRowNo(record);
  kintone.app.record.set({record: record});
};

削除する行番号を取得し、targetRowNo に格納します。

71
const targetRowNo = record.削除_行番号.value;

forEach() を利用して、テーブルの行数分ループ処理します。
ループ中、指定された行番号と同じ行を削除します。

71
72
73
74
75
record.テーブル.value.forEach((row, i) => {
  if (row.value.行番号.value === targetRowNo) {
    record.テーブル.value.splice(i, 1);
  }
});

行の削除には .splice() を使います。

テーブルの行番号を更新する処理

下記は行番号を更新する関数です。
行を追加したり削除したりすると行番号がずれるため、行番号を振り直す処理が必要です。
行の更新や削除の処理と同様 forEach() を使い、行番号を「1」から順番に振り直します。

81
82
83
84
85
86
// 行番号を更新する関数
const resetRowNo = (record) => {
  record.テーブル.value.forEach((row, i) => {
    row.value.行番号.value = i + 1;
  });
};

最後に

今回はテーブルの作成・更新・削除やそのためにボタンを設置するなど、複合的なサンプルになっており行数も多いですが、1 つ 1 つは難しくなく、少しずつ積み重ねれば書けるものだと思います。
たとえば、「追加だけ試す」「ボタンを表示するところだけ試す」など、気になる部分だけでも少しずつ試してもらえればと思います。

デモ環境

デモ環境で実際に動作を確認できます。
https://dev-demo.cybozu.com/k/316/ (External link)

ログイン情報は cybozu developer network デモ環境 で確認してください。

information

この記事は、2022 年 6 月版 kintone で動作を確認しています。