Handsontable を使って kintone を Excel ライクに入力しよう その 1 - 基本編

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

目次

はじめに

kintone はブラウザーからレコードの一覧の表示や編集ができますが、Excel のような画面で閲覧・編集がしたいという要望を度々聞きます。
今回は Cybozu CDN で公開されている、 Handsontable (External link) を使って Excel ライクな入力を実現してみました。
やり方を以下にまとめますので、興味のある方はぜひ試してみてください。

Handsontable とは

ホームページ: Handsontable (External link)

Handsontable は、Excel のようなスプレッドシートライクな入力を可能にしてくれる JavaScript ライブラリです。
サンプルページ (External link) で試すとわかりますが、Excel のようにデータ入力ができるだけでなく、セルの書式の指定やチャートが作れたりと、機能が多いのも魅力です。

kintone カスタマイズでの導入方法

実際に、Handsontable(無償版)を kintone のカスタマイズに利用してみましょう。

デモ環境

デモ環境 (External link) で実際に動作を確認できます。
ログイン情報は cybozu developer network デモ環境 で確認してください。

サンプルアプリの準備

まずはアプリの準備をします。

フィールドの設定

サンプルアプリのフィールドは以下です。
フィールド名とフィールドコードは同一にしました。

フィールド名(フィールドコード) フィールドタイプ
レコード番号 レコード番号
会社名 文字列(1 行)
先方担当者名 文字列(1 行)
見込み時期 日付
確度 ラジオボタン
製品名 ドロップダウン
単価 数値
ユーザー数 数値
小計 計算
一覧の設定

アプリの一覧は、カスタマイズビューを用います。
スプレッドシート表示のための要素を HTML で記述します。

1
<div id="sheet"></div>

カスタマイズビューについての詳細は、 第 7 回 カスタマイズビューを利用してみよう を参照ください。

JavaScript / CSS の設定

今回は Cybozu CDN に登録されているものを利用します。
Cybozu CDN には JavaScript だけでなく CSS ファイルも提供されている上、キャッシュも有効になっているので高速化を図れるという利点があります。
今回は version 6.2.2 を利用します。
アプリの JavaScript/CSS 設定画面には、下記 URL を指定します。

  • JavaScript URL
    https://js.cybozu.com/handsontable/6.2.2/handsontable.full.min.js
  • CSS URL
    https://js.cybozu.com/handsontable/6.2.2/handsontable.full.min.css
information

カスタマイズで利用している Handsontable は、v7.0.0 以降は MIT ライセンスではなく有償です。
このカスタマイズでは、 MIT (External link) ライセンスの v6.2.2 を利用しています( ライセンス表記 (External link) )。
v7.0.0 以降を利用する際は Handsontable の HP (External link) で有償ライセンスを購入し、ライセンス条件にしたがって利用してください。
詳細は、 Cybozu CDN ライセンス対応ガイド を参照してください。

データの入力

確認のために、サンプルデータを先に数件入力しておきましょう。

JavaScript プログラミング

実際に JavaScript でプログラミングしていきます。
Handsontable の仕様や使い方は Handsontableの公式ドキュメント(v6.2.2) (External link) を参照ください。

Handsontable の使い方

次のように指定するだけでスプレッドシートの表示が可能です。
Handsontable の data オプションに kintone のレコードデータを指定すればバインドできそうです。

1
2
3
4
5
6
7
8
const container = document.getElementById('sheet');
new Handsontable(container, {
  data: data, // 配列やオブジェクトのデータを指定
  minSpareRows: 1, // 下部の余白行の指定
  rowHeaders: true, // 列ヘッダを表示
  colHeaders: true, // 行ヘッダを表示
  contextMenu: true // 右クリックメニューを表示
});
スプレッドシートにレコードを一覧表示する

まずは単純に kintone のレコードをスプレッドシートに表示してみます。
Handsontable の data オプションには、kintone のレコードデータを指定し、columns には フィールド名.value と指定することで、kintone のレコードデータをそのまま反映できます。
必要に応じて、colHeaders オプションに配列を指定することで、ヘッダー行も指定できます。
viewId はカスタマイズビュー設定時の viewId を入力してください。

 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
/*
 * show kintone record like Excel by handsontable sample program
 * Copyright (c) 2022 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
*/
(() => {
  'use strict';
  kintone.events.on(['app.record.index.show'], (event) => {
    // ビューIDを指定する(指定したビューID以外は処理しない)
    if (event.viewId !== 7199) return;
    const records = event.records;
    // カスタマイズビュー設定時に登録したHTMLの要素を指定します。
    const container = document.getElementById('sheet');
    container.innerHTML = ''; // ページ送りするとき重複してHandsontableが表示されないように初期化
    // Handsontableをインスタンス化
    new Handsontable(container, {
      // kintoneのレコードデータを指定
      data: records,
      minSpareRows: 0,
      // カラムのヘッダーを指定
      colHeaders: ['レコード番号', '会社名', '先方担当者名', '見込み時期', '確度', '製品名', '単価', 'ユーザー数', '小計'],
      contextMenu: false,
      // dataオプションのどの列を表示するか指定する。
      columns: [
        {data: 'レコード番号.value'},
        {data: '会社名.value'},
        {data: '先方担当者名.value'},
        {data: '見込み時期.value'},
        {data: '確度.value'},
        {data: '製品名.value'},
        {data: '単価.value'},
        {data: 'ユーザー数.value'},
        {data: '小計.value'}
      ]
    });
  });
})();

これで kintone に登録したデータを Excel のように表示できるようになるはずです。

スプレッドシートに表示したレコードを更新する

表示はできたので、その表示されたデータを更新できるようにします。
データの更新時、afterChange オプションに指定したメソッドが呼び出されるので、そのメソッドを利用して kintone のアップデート処理を行います。
また、columns オプションを指定するときは、編集されたくないデータを readOnly に指定できます。

 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
/*
 * update kintone record like Excel by handsontable sample program
 * Copyright (c) 2022 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
*/
(() => {
  // レコードを保存するためのメソッド
  'use strict';
  const saveRecords = (records, callback, errorCallback) => {
    kintone.api(kintone.api.url('/k/v1/records', true), 'PUT', {app: kintone.app.getId(), records: records},
      (resp) => {
        callback(resp);

      },
      (resp) => {
        errorCallback(resp);
      });
  };
  // kintoneのレコード更新時は、レコード番号などアップデートできないフィールドがあるので、除外するためのメソッド
  const setParams = (record) => {
    const result = {};
    for (const prop in record) {
      if (['レコード番号', '作成日時', '更新日時', '作成者', '更新者'].indexOf(prop) === -1) {
        result[prop] = record[prop];
      }
    }
    return result;
  };
    // 一覧ビュー表示用のイベントハンドラ
  kintone.events.on(['app.record.index.show'], (event) => {
    // ビューIDを指定する(指定したビューID以外は処理しない)
    if (event.viewId !== 7199) return;
    const records = event.records;
    const container = document.getElementById('sheet');
    container.innerHTML = ''; // ページ送りするとき重複してHandsontableが表示されないように初期化

    new Handsontable(container, {
      data: records,
      minSpareRows: 0,
      colHeaders: ['レコード番号', '会社名', '先方担当者名', '見込み時期', '確度', '製品名', '単価', 'ユーザー数', '小計'],
      contextMenu: false,
      // 必要に応じてreadOnlyの指定ができます。
      columns: [
        {data: 'レコード番号.value', readOnly: true},
        {data: '会社名.value'},
        {data: '先方担当者名.value'},
        {data: '見込み時期.value'},
        {data: '確度.value'},
        {data: '製品名.value'},
        {data: '単価.value'},
        {data: 'ユーザー数.value'},
        {data: '小計.value', readOnly: true}
      ],
      // スプレッドシートのセルが更新されると、下記メソッドが呼び出されます。
      // 呼び出されるaftarChangeメソッドは、引数changeに変更されたセルの詳細がわかり、引数sourceは何によって変更されたかがわかります。
      afterChange: (change, source) => {
        if (source === 'loadData') {
          return;
        }
        let i;
        const targets = [];
        // 引数changeのデータを読み取り、kintoneへ更新APIを発行します。
        for (i = 0; i < change.length; i++) {
          targets.push({
            id: records[change[i][0]]['レコード番号'].value,
            record: setParams(records[change[i][0]])
          });
        }
        saveRecords(targets, (resp) => {
          console.dir(resp);
        }, (resp) => {
          console.dir(resp);
        });
      }
    });
  });
})();

afterChange メソッドの引数 Change は次の配列が格納されます。
上記の例では、"変更があったセルの行数"を参照しどのレコード番号のデータを変更するかを指定しています。

1
2
3
4
5
6
7
8
9
// 10行目、先方担当者名が編集された場合の例
[
  [
    9, // 変更があったセルの行数
    '先方担当者名.value', // 変更があったセルの列名
    'テスト太郎', // 変更される前のデータ
    'テスト次郎' // 変更された後のデータ
  ]
];

ちなみに、データのバインディングは自動で行われますので、スプレッドシート上で変更したデータは、kintone の event.records 変数にすでに反映されています。
便利ですね。

おわりに

今回は、Handsontable を用いて、Excel ライクな見た目で、レコードの表示と編集が行えるように kintone をカスタマイズしました。
次回は、 Handsontable を使って kintone を Excel ライクに入力しよう その 2 - 基本編 でレコードの追加やプルダウンによる選択などを試してみます。

information

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