Skip to content

Instantly share code, notes, and snippets.

@mura-
Last active September 18, 2023 05:45
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mura-/b06966117dd25aaedd64 to your computer and use it in GitHub Desktop.
Save mura-/b06966117dd25aaedd64 to your computer and use it in GitHub Desktop.
kintone x handsontable
(() => {
'use strict';
let hot; // handsontable用変数
// kintoneのレコード更新・追加時は、レコード番号などアップデートできないフィールドがあるので、除外するためのメソッド
const setParams = (record) => {
const result = {};
for (const prop in record) {
if (['レコード番号', '作成日時', '更新日時', '作成者', '更新者', 'ステータス', '作業者'].indexOf(prop) === -1) {
result[prop] = record[prop];
}
}
return result;
};
// kintoneのレコード取得用メソッド
const getRecords = (callback, errorCallback) => {
kintone.api('/k/v1/records', 'GET', {app: kintone.app.getId(), query: 'order by レコード番号 asc limit 500'},
(resp) => {
callback(resp);
},
(resp) => {
errorCallback(resp);
}
);
};
// kintoneのレコード更新、追加用メソッド
const saveRecords = (records, changedDatas, callback, errorCallback) =>{
const requests = [];
const updateRecords = [];
const insertRecords = [];
let changedRows = [];
// 変更されたセルの配列から、変更があった行だけ抜き出す
for (let i = 0; i < changedDatas.length; i++) {
changedRows.push(changedDatas[i][0]);
}
// 変更があった行番号の重複を排除
changedRows = changedRows.filter((x, i, self) => {
return self.indexOf(x) === i;
});
// 変更があった行から、レコード追加か変更かを判断し、クエリをつくる
for (let i = 0; i < changedRows.length; i++) {
if (records[changedRows[i]]['レコード番号'].value === null) {
insertRecords.push(
setParams(records[changedRows[i]])
);
} else {
updateRecords.push({
id: records[changedRows[i]]['レコード番号'].value,
record: setParams(records[changedRows[i]])
});
}
}
// 更新用bulkRequest
requests.push({
method: 'PUT',
api: '/k/v1/records.json',
payload: {
app: kintone.app.getId(),
records: updateRecords
}
});
// 追加用bulkRequest
requests.push({
method: 'POST',
api: '/k/v1/records.json',
payload: {
app: kintone.app.getId(),
records: insertRecords
}
});
// bulkrequestで一括で追加、更新。
// 失敗した場合はロールバックされる。
kintone.api('/k/v1/bulkRequest', 'POST', {requests: requests},
(resp) => {
console.dir(requests);
console.dir(resp);
callback(resp);
},
(resp) => {
errorCallback(resp);
}
);
};
// kintoneのレコード削除用メソッド
const deleteRecords = (records, index, amount, callback, errorCallback) => {
let i;
const ids = [];
for (i = index; i < index + amount; i++) {
ids.push(records[i]['レコード番号'].value);
}
kintone.api('/k/v1/records', 'DELETE', {app: kintone.app.getId(), ids: ids},
(resp) => {
callback(resp);
},
(resp) => {
errorCallback(resp);
}
);
};
// 定期的にkintone上のデータを再取得する
const autoload = () =>{
getRecords((resp)=> {
hot.loadData(resp.records);
});
setTimeout(()=> {
autoload();
}, 10000); // 10秒。APIの呼び出し数の上限があるので、必要に応じて変更してください。
};
// 一覧ビュー表示用のイベントハンドラ
kintone.events.on(['app.record.index.show'], (event) => {
if (event.viewId !== 5263125) return;
const container = document.getElementById('sheet');
// handsontable初期化
hot = new Handsontable(container, {
// この時点ではdataは入力せず、あとから読み込ませるようにする。(データ更新時も再読み込みさせたいため)
data: [],
// 空白行
minSpareRows: 10,
// 表示したいカラム
colHeaders: ['レコード番号', '会社名', '先方担当者名', '見込み時期', '確度', '製品名', '単価', 'ユーザー数', '小計'],
// コンテキストメニュー(右クリックメニュー)を指定。今回は削除用メニューのみ。
contextMenu: ['remove_row'],
// 必要に応じてreadOnlyの指定ができます。
columns: [
{data: 'レコード番号.value', readOnly: true},
{data: '会社名.value'},
{data: '先方担当者名.value'},
{data: '見込み時期.value'},
{data: '確度.value'},
{data: '製品名.value'},
{data: '単価.value'},
{data: 'ユーザー数.value'},
{data: '小計.value', readOnly: true}
],
// スプレットシート上のレコードを削除したときに呼び出されるイベント
// 引数indexは削除する行
// 引数amountは削除する行数
beforeRemoveRow: (index, amount) => {
// kintoneのレコードを削除する
deleteRecords(hot.getSourceData(), index, amount,
(deleteRecordsResp)=> {
console.dir(deleteRecordsResp);
getRecords((getRecordsResp)=> {
// 削除後、データを再読み込み
hot.loadData(getRecordsResp.records);
});
},
(resp)=> {
console.dir(resp);
}
);
},
// スプレットシート上のレコードが編集されたときに呼び出されるイベント
afterChange: (change, source) => {
console.log(source);
// データ読み込み時はイベントを終了
if (source === 'loadData') {
return;
}
// kintoneのレコードを更新、追加する
saveRecords(hot.getSourceData(), change,
(resp)=> {
console.dir(resp);
getRecords((saveRecordsResp)=> {
// 更新後、データを再読み込み
hot.loadData(saveRecordsResp.records);
},
(getRecordResp)=> {
// レコード取得失敗時に呼び出される
console.dir(getRecordResp);
});
},
(resp)=> {
// 更新・追加時に呼び出される
console.dir(resp);
}
);
}
});
// レコードを取得してhandsontableに反映
getRecords((resp)=> {
hot.loadData(resp.records);
autoload();
});
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment