Edited at

【Handsontable】カレンダーの日本語化とセルにカスタムHTML表示など


はじめに

これは、Handsontable Advent Calendar 2018の25日目の記事となります。


カレンダーの日本語化

hotCalendar.png

Handsontableのカレンダー表示は、内部では Pikaday.js を使用している。

カレンダー設定は、datePickerConfigオプションで細かな変更が可能。

例えば、firstDayを1にすると月曜始まりのカレンダーとなる。工場を持つ企業などで使われている。※各設定の意味は、PikaDay.jsメモ を参考にする。

datePickerConfig: {

// First day of the week (0: Sunday, 1: Monday, etc)
firstDay: 1
}

カレンダーの日本語化するには、NuGetにて「Moment.js」をインストールする。

「moment.locale('ja');」を実行すれば、monthsとweekdaysとweekdaysShortは、Momentから取得できる。

<script src="../Scripts/moment-with-locales.min.js"></script>

// 日本語化

moment.locale('ja');

var hot = new Handsontable(grid, {

columns: [
{ data: COL_SHIPMENTDATE, type: 'date', width: 150,
dateFormat: 'YYYY/MM/DD',
datePickerConfig: {
yearSuffix: '',
showMonthAfterYear: true,
showDaysInNextAndPreviousMonths: true,
i18n: {
previousMonth: '前月',
nextMonth: '次月',
months: moment.localeData()._months,
weekdays: moment.localeData()._weekdays,
weekdaysShort: moment.localeData()._weekdaysShort
}
},
validator: function (value, callback) { callback(true); }
},


土日の色を変更する

CSS3の擬似クラスを使用して、色を変更する。handsontable用のcssファイルに含めて置き換えてもいいし、外出しにしてもいい。

何番目系の便利なCSSまとめ


日曜始まり

.pika-lendar th:first-child,

.pika-lendar td:first-child .pika-button {
color: #f00;
}
.pika-lendar th:last-child,
.pika-lendar td:last-child .pika-button {
color: #00f;
}


月曜始まり

.pika-lendar th:nth-last-child(2),

.pika-lendar td:nth-last-child(2) .pika-button {
color: #00f;
}
.pika-lendar th:last-child,
.pika-lendar td:last-child .pika-button {
color: #f00;
}

Pikaday.js 祝日対応とMoment不使用フォーマット整形


セルにカスタムHTML表示

HTMLを表示できるので、リンクや画像を表示できる。

Rendering custom HTML in cells

hotCellCustom.png


セルにボタン表示

標準ではボタンは用意されていないが、HTMLを表示出来ることを利用する。

http://jsfiddle.net/handsoncode/zram5uaL/

https://jsbin.com/heqijexeci/1/edit?html,js,output

DateTimePickerの時間を組み合わせて、ボタンを押したら時間入力ダイアログを表示して時間をセットする。

StartTime.png

inputTime.png

Bootstrap 4でDatetimePickerを使いたい

$('#datetimepicker1').on('change.datetimepicker', function(e) {

if(selectedCol === 0) return;
hot.setDataAtCell(selectedRow, selectedCol, e.date.format("HH:mm"));
});

function myBtns(instance, td, row, col, prop, value, cellProperties) {
Handsontable.renderers.TextRenderer.apply(this, arguments);
if (value === null) value = "00:00";
td.innerHTML = '<button class="myBtn bt-' + row + '">' + value + '</button>'
}

var hot = new Handsontable(grid, {

cells: function(row, col) {
var cellPrp = {};
if (col === 5) {
cellPrp.renderer = myBtns;
cellPrp.readOnly = true;
}
return cellPrp
},
afterOnCellMouseDown: function(event, cords, TD) {
if (event.realTarget.className.indexOf('myBtn') < 0) {
return;
}

var time = hot.getDataAtCell(selectedRow, selectedCol);
if (time === null) time = "00:00";
$('#datetimepicker1').data("datetimepicker").defaultDate(moment(moment().format('L') + ' ' + time));
$('#timeModal').modal();
}
afterSelection: function (r, c, r2, c2) {
// ボタンとかおしてフォーカスがGridから離れると
// getSelected() では取れなくなるので、
// このタイミングで常に保持しておいたほうが無難
selectedRow = r2;
selectedCol = c2;
}

}


列の非表示

列の非表示はPRO版では実装されています。

フリー版で実現する際は特定の列の幅を0.1ピクセルにして実現させます。

技術的にはテーブルの一部であり、getData() は列のデータを返しますが、人間の目には見えません。

※IE11では、チェックボックスにしていたためかセルが表示されてしまう不具合があります。

但し、セル移動した際に非表示列にもフォーカスが移動してしまいます。

hotHiddenColumn.png

var hot = new Handsontable(grid, {

columns: [
{ data: "DBRead", type: 'text', width: 0.1 }


非表示列の値の取得

バインドしてある前提で、幅を 0.1 にしなくても非表示列の値が取得できる方法があります。※この際に非表示列を設定する必要はありません。

var hot = new Handsontable(grid, xxx);

if (hot.getSourceDataAtCell(row, "DBRead") === true)

※DBから読んだデータと新規入力のデータと分ける上で DBRead列が true で判定する場合を想定。

getSourceDataAtCell returns same as getDataAtCell


Jsonデータのまま保存する

Jsonデータを loadData メソッドで Handsontable でデータにロードした場合、データを保存する時にもJsonデータのままサーバー側に渡したい場合、getData ではなく getSorceData を使用する。

Posting Handontable JSON using Ajax to ASP.net MVC controller not working Since "0.22.0"


getSourceDataとgetDataの違い


  • getSourceData() で取得したデータは元となったデータ src と同じインスタンスを指している。

  • 一方で、 getData() で取得したデータは、元のデータとは別のインスタンスになっている。

getSourceData:ソースデータをそのまま取得する


リサイズでサイズ変更する

リサイズ後にサイズを変更する。

リサイズ後(resized)イベントは、下記サイトを参考

JavaScript で window リサイズ終了後のタイミングをハンドリングする方法

Bootstrapのグリッドシステムを採用している場合、divタグに"id=Box"属性を付けて横幅を取得する。

その横幅を少し小さめにHandsonTableのwidthにセットしている。そうしないと縦スクロールバーが見えなくなってしまう。

縦幅は最低限表示するサイズ(150)と、最大で表示するサイズ(400)を指定している。

var resizeTimer;

var interval = Math.floor(1000 / 60 * 10);

// リサイズ完了時
window.addEventListener('resize', function (event) {
if (resizeTimer !== false) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(function () {
resize();
}, interval);
})

// リサイズ
function resize() {
var client_w = document.getElementById('box').clientWidth;
var client_h = window.parent.screen.height;
//alert("Resized client_w:" + client_w + " x client_h:" + client_h);

hot.updateSettings({
width: client_w - 20,
height: Math.min(Math.max(150, client_h - 440), 400)
});
}


その他


最後に

Handsontable Advent Calendar 2018 の最後の記事でした。

お読み頂いた皆様ありがとうございます。

使いこなすにはあまりある機能満載なライブラリーなので、また記事を増やしていきたいと思っています。