WEBでExcel風の一覧を再現するHandsontableを使って、クライアント側で更新、登録、削除機能を実装しました。今回は編集データをSubmitする仕組みを整備します。
振り返り(クライアント側の編集)
変更の種類には追加(Ins)と変更(Upd)と削除(Del)がありますが、クライアント側では下記のようになっています。これらの変更は、クライアント側での編集状態でしかありません。「反映」ボタンを押下することにより、サーバサイドにSubmitできる仕組みを作ります。

クライアント側の実装は以前記載しました。
https://itdkt.info/archives/177
https://itdkt.info/archives/196
Ins行には”テスト”と入力して 反映ボタン押下後は下記のようになります。
Submitの仕組み
前提として、Ruby On Railsのフォームの仕組みは使えません。form_forの仕組みは最終的にformタグとそれに囲まれたinputタグ(など)に展開されるので、ブラウザの機能で指定パスにPOST、ないしGETリクエストが送信されます。対してhandsontableは所詮はdivタグであり、そのままではSubmitされません。

そこで、Submitボタン(=上記画像では”反映ボタン”)にするためのmyライブラリを作成しました。
ライブラリ実装
(function($) {
'user strict';
//(中略)
var postAjax = function(action, method, data, callBack) {
$.ajax({
url: action,
type: method,
data: data,
dataType: 'json',
contentType: 'application/json; charset=utf-8',
async: true,
processData: true,
cache: false
}).fail(function(xhr, status, error) {
var dialog = $('<div></div>').text(xhr.responseJSON.message);
dialog.dialog({
modal: true,
title: "エラーがあります.",
buttons: [{
text: 'OK',
click: function() { $(this).dialog('close'); }
}]
});
}).done(function(d) {
if (callBack === undefined) {} else {
callBack(d);
}
});
}
//(中略)
/*
* hot: handsontableのオブジェクト
* beforeFunc: POST前に実行するファンクション.文字列を返すとエラーメッセージとして表示し、POSTを中断する。
* successFunc: POST後に実行される.-> jqueryのajaxのdone(function (data))
*/
$.fn.commitHandson = function(hot, beforeFunc = undefined, successFunc = undefined) {
this.bind('click', function(e) {
e.preventDefault();
e.stopPropagation();
let action = $(this).attr('href');
let method = $(this).attr('data-method');
if (beforeFunc === undefined) {} else {
//エラーメッセージがnull以外ならばpostせずに終わる.
var errmsg = beforeFunc()
if (errmsg != null) {
var dialog = $('<div></div>').text(errmsg);
dialog.dialog({
modal: true,
title: "エラーがあります.",
buttons: [{
text: 'OK',
click: function() { $(this).dialog('close'); }
}]
});
return;
}
}
postAjax(action, method, JSON.stringify(hot.getSourceData()), successFunc);
});
}
})(jQuery);
//処理成功後にダイアログを出しながらファンクション実行する
function concreateSuccess(handleFunc = undefined) {
var success = function(data) {
var dialog = $('<div></div>').text("反映しました.");
dialog.dialog({
modal: true,
title: "結果確認",
buttons: [{
text: 'OK',
click: function() { $(this).dialog('close'); }
}]
});
if (handleFunc == undefined) {} else {
handleFunc(data);
}
}
return success;
}
画面側の実装
反映ボタンのソースと、反映ボタンへのバインドを示します。見た目はBootstrapのクラスが反映されていますが、お好みで指定してください。POST先は、railsのパスファンクションで作ります。methodは必須ですが、routes.rbと合致するように指定します。
<%= link_to '反映', setting_path("d"), method: "PATCH",
class: "btn btn-labeled btn-success btn-custom", id: "commitBtn" %>
なお、サーバサイドからのレスポンスを更新後の一覧データを受け取って再描画するようにしています。
var reload = function(resJson){
settings = hot.getSettings();
settings.data = eval(resJson.data);
hot.updateSettings(settings);
}
$('#commitBtn').commitHandson(hot, undefined, concreateSuccess(reload));
サーバが受け取るリクエスト
確かなところではサーバサイドでputs paramsしていただきたいのですが、イメージとしては下記のようにリクエストが渡ってきます。
[{
"id" => 11,
"man_hour_name" => "Ruby On Rails",
"results" => 0,
"valid_from" => "2019/12/31",
"valid_to" => "2025/12/31",
"status" => "Upd"
},{
"id" => 12,
"man_hour_name" => "ゲーム",
"results" => 0,
"valid_from" => "2019/12/31",
"valid_to" => "2025/12/31",
"select" => true,
"status" => "Del"
},{
"id" => nil,
"man_hour_name" => "テスト",
"results" => nil,
"valid_from" => "2019/12/31",
"valid_to" => "2025/12/31",
"status" => "Ins"
}]