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で動作を確認しています。