WijmoのFlexGridを利用してテーブルをExcelライクに入力する

注文書のようなアプリで明細行をテーブルで作成して、詳細画面にてExcelライクに入力するサンプルコードです。

Wijmoのトライアル版をこちらからダウンロードして、「JavaScript / CSSでカスタマイズ」に追加します。

  • wijmo.min.js
  • wijmo.grid.min.js
  • wijmo.culture.ja.min.js

サンプルコードではunderscore.jsを利用していますので下記も追加します。

 

サンプルコード

(function() {
    "use strict";
    kintone.events.on(["app.record.edit.show","app.record.create.show"], function(e) {

        var record = e.record;

        // 明細をFlexgridに表示
        showContent(record["明細"].value);
        // 標準の明細を隠す
        kintone.app.record.setFieldShown("明細", false);

        return e;
    });

    var columnTypes;
    
    /**
     * KintoneデータをFrexgridに表示します
     * @param {Object} records
     */
    var showContent = function (records) {

        columnTypes = getColumnTypes(records);
    
        var dataList = convertToArray(records);
        var cv = new wijmo.collections.CollectionView(dataList);
        var grid;

        // FlexGridを生成
        var gridSpace = kintone.app.record.getSpaceElement("flexgrid");
        if (_.isEmpty(gridSpace.innerHTML)) {
            grid = new wijmo.grid.FlexGrid(gridSpace);
            grid.initialize({
                autoGenerateColumns: false,
                itemsSource: cv,
                allowAddNew: true,
                allowSorting: false,
                allowDelete: true,
                imeEnabled: true,
                columns: [{
                    binding: 'id',
                    visible: false,
                }, {
                    binding: '内容',
                    width: 200,
                }, {
                    binding: '規格',
                    width: 200,
                }, {
                    binding: '単価',
                }, {
                    binding: '数量',
                    width: 80,
                }, {
                    binding: '金額',
                    isReadOnly: true,
                }],
            });
            
            // セル編集が確定またはキャンセルされたとき
            grid.cellEditEnded.addHandler(function (sender, event) {
                // 金額を計算する。
                var column = sender.columns[event.col];
                if (column.binding == "数量" || column.binding == "単価") {
                    calcAmount(sender, event.row);
                    updateContent(sender);
                }
            });

            // 行が追加されたとき
            grid.rowAdded.addHandler(function (sender, event) {
                updateContent(sender);
            });

            // 行が削除されたとき
            grid.deletedRow.addHandler(function (sender, event) {
                updateContent(sender);
            });

            // セルにペーストしたとき
            grid.pastedCell.addHandler(function (sender, event) {
                var fromRow = event.range.row;
                var toRow = event.range.row2;
                for (var row = fromRow; row <= toRow; row ++) {
                    calcAmount(sender, row);
                }
                updateContent(sender);
            });
            
        } else {
            grid = wijmo.Control.getControl(gridSpace);
            grid.itemsSource = cv;
        }
    };
    
    /**
     * Flexgridの内容をKintoneのrecordに反映します
     */
    var updateContent = function(grid) {

        var dataList = grid.itemsSource.items;
        var items = [];
        for (var i = 0; i < dataList.length; i ++) {
            var item = {};
            item.value = {};
    
            if (!_.isEmpty(dataList[i].id)) {
                item.id = dataList[i].id;
            }
    
            for (var key in columnTypes) {
                item.value[key] = {};
                var value = null;
                if (_.has(dataList[i], key)) {
                    value = dataList[i][key];
                }
                // isEmpty(1)がtrue判定されるのでisNullで判定している
                if (_.isNull(value)) {
                    // 未入力エラーを回避する
                    if (columnTypes[key] == "NUMBER" || columnTypes[key] == "CALC") {
                        value = 0;
                    } else {
                        value = "";
                    }
                }
                item.value[key].value = value;
                item.value[key].type = columnTypes[key];
            }
            items.push(item);
        }
        var record = kintone.app.record.get();
        record.record["明細"].value = items;
        kintone.app.record.set(record);
        
    };
    
    /**
     * 金額を計算します
     * @param {Object} grid FlexGrid
     * @param {Number} row 行インデックス
     */
    var calcAmount = function (grid, row) {
        var quantity = 0;   // 数量
        var tanka = 0;      // 単価
        var value;
        value = grid.getCellData(row, grid.columns.indexOf("数量"), false);
        if (!_.isNull(value) && !_.isUndefined(value)) {
            quantity = value;
        }
        value = grid.getCellData(row, grid.columns.indexOf("単価"), false);
        if (!_.isNull(value) && !_.isUndefined(value)) {
            tanka = value;
        }
        var amount = Math.floor(tanka * quantity);
        grid.setCellData(row, grid.columns.indexOf("金額"), amount);
    };

    /**
     * FlexgridカラムのKintoneのデータタイプ情報を取得します。
     * @param {Object} kintoneのtype-value型のレコード
     * @returns {Object} Key-Valueハッシュ
     */
    var getColumnTypes = function (records) {
        var columnTypes = {};
    
        if (records.length > 0) {
            for (var key in records[0].value) {
                columnTypes[key] = records[0].value[key].type;
            }
        }
        return columnTypes;
    };

    /**
     * kintoneのtype-value型のレコードをFlexgrid用のオブジェクト配列に変換
     * @param {Object} kintoneのtype-value型のレコード
     * @returns {Object} 変換後の配列
     */
    var convertToArray = function (records) {

        var datas = [];

        for (var i = 0; i < records.length; i++) {
            var data = {};
            data.id = records[i].id;
            for (var key in records[i].value) {
                if (records[i].value[key].type === 'NUMBER' || records[i].value[key].type === 'CALC') {
                    data[key] = Number(records[i].value[key].value);
                } else {
                    data[key] = records[i].value[key].value;
                }
            }
            datas.push(data);
        }
        return datas;
    };

})();

大事なことが抜けてました。スペースを追加してIDにflexgridを設定してください。