4. テーブル

この章では、テーブルのライブラリであるSlickGrid、tablesorterを用いた実装例を説明する。

それぞれのライブラリが実現できる機能は、次の表の通りである。

ライブラリが実現できる機能
機能 SlikGrid tablesorter
行追加・削除・編集
行の並び替え
ヘッダを固定したデータ行のスクロール
ページネーション
ソート
カラムの並び替え
コピーアンドペースト編集
テーブルのスクロールによる非同期データ取得

どちらのライブラリを使用するかは、上に示した機能や、特徴 (SlickGrid概要およびtablesorter概要) を参考にして判断すること。

また、SlickGridとBootstrapを同時に使用する場合、付録の注意点を考慮すること。

Note

SlickGridはテーブルのセル数に応じてDOMが変化する。また、スクロールを行い表示内容が変化するタイミングでDOMの書き換えが発生する。 テーブルのセル数が多い場合、スクロール操作の度に多数のDOMを書き換える必要があり、大きなオーバーヘッドが発生することがあるため、十分に検証を行った上で採用すること。

4.1. ライブラリの基本的な使用方法

ここでは、テーブルを扱うライブラリであるSlickGridとtablesorterの基本的な使用方法を説明する。

利用ライブラリ サンプル 参考ページ
SlickGrid SlickGrid基本構成サンプル SlickGrid Wiki
tablesorter tablesorter基本構成サンプル jQuery plugin: Tablesorter 2.0

4.1.1. SlickGrid基本構成サンプル

HTMLでは、SlickGrid用のスタイルシート、依存ライブラリ、SlickGridモジュール、さらにSlickGridでテーブルを生成するために実装したJavaScriptファイル(js/default.js)を読み込む。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>SlickGrid基本構成サンプル</title>

    <!-- SlickGrid用のスタイルシートの読み込み -->
    <link rel="stylesheet" href="../lib/vendor/slickgrid/2.1.0/slick.grid.css">

    <link rel="stylesheet" href="css/main.css">
  </head>
  <body>

    <h1>SlickGrid基本構成サンプル</h1>

    <!-- SlickGridテーブルの表示領域となる要素 -->
    <div id="myGrid" class="grid" style="grid"></div>

    <!-- 依存ライブラリの読み込み -->
    <script src="../lib/vendor/jquery/1.11.1/jquery-1.11.1.min.js"></script>
    <script src="../lib/vendor/jquery.event.drag-drop/2.2/jquery.event.drag.js"></script>
    <script src="../lib/vendor/jquery-ui/1.11.1/jquery-ui.min.js"></script>

    <!-- SlickGridモジュールの読み込み -->
    <script src="../lib/vendor/slickgrid/2.1.0/slick.core.js"></script>
    <script src="../lib/vendor/slickgrid/2.1.0/slick.grid.js"></script>

    <!-- 実装したJavaScriptファイルの読み込み -->
    <script src="js/default.js"></script>
  </body>
</html>

JavaScript(js/default.js)では、Slick.Gridコンストラクタを実行することで、指定した領域にテーブルを生成する。 Slick.Gridコンストラクタのシグネチャは次のとおり。

Slick.Grid(container, data, columns[, options])
Arguments:
  • container (String) – テーブルの表示領域となる要素のセレクタ
  • data (Array|DataView|Object) – テーブルで扱うデータ配列。データの表示条件をより詳細に制御する場合は、配列の代わりに、DataViewオブジェクトや、getLengthgetItem関数を持つオブジェクトを指定することもできる。
  • columns (Array) – カラム定義。各カラムごとに表示名やデータ項目などのプロパティをもつオブジェクトを配列で複数指定する。
  • options (Object) – 動作オプション
// default.js

'use strict';

(function () {

  // (1) SlickGridのカラム定義
  //     6つのカラムのそれぞれにつき ID・表示名・マッピングするデータ を定義している。
  var columns = [
    {id: 'title', name: 'Title', field: 'title'},
    {id: 'duration', name: 'Duration', field: 'duration'},
    {id: '%', name: '% Complete', field: 'percentComplete'},
    {id: 'start', name: 'Start', field: 'start'},
    {id: 'finish', name: 'Finish', field: 'finish'},
    {id: 'effort-driven', name: 'Effort Driven', field: 'effortDriven'}
  ];

  // (2) SlickGridの動作オプション
  var options = {

    // 何も指定しない。
  };

  // (3) 1000件のサンプルデータ作成
  var data = [];
  for (var i = 0; i < 1000; i++) {

    // データのプロパティ名を columns で定義した field 値と一致させることで、
    // 表示データがマッピングされる。
    data[i] = {
      title: 'タスク ' + i,
      duration: '5 days',
      percentComplete: Math.round(Math.random() * 100),
      start: '01/01/2009',
      finish: '01/05/2009',
      effortDriven: (i % 5 === 0) ? 'true' : 'false'
    };
  }

  // 画面初期化処理
  $(function () {

    // (4) SlickGridテーブルを作成
    new Slick.Grid('#myGrid', data, columns, options);
  });

}());

カラム定義は、ソースコードリスト上の(1)で行っている。この例では6列のカラムを定義し、それぞれIDやヘッダの表示テキスト(name)、表示データ名(field)を指定している。

オプションの設定は(2)で行う。この例は基本構成なのでオプションは指定しないが、以降のサンプルではここに設定を追加していく。

データの作成は(3)で行っている。この例では1000件のデータを作成している。各データのtitleなどのデータは、カラム定義のfieldプロパティと一致するカラムに表示される。意図した通りにデータが表示されない場合は、カラム定義とデータのプロパティ名が一致していない可能性があるため、見直すこと。

最後に(4)で、これらの設定値やデータを用いて Slick.Grid コンストラクタを実行しテーブルを作成している。

Note

SlickGridには様々な依存ライブラリやスタイルシート、機能拡張用モジュールがあり、使用する機能に応じてこれらを読み込む必要がある。以下に、それぞれのファイルがどのような際に必要とされるかをまとめている(用途の少ないものは省略している)。

依存ライブラリ
依存ライブラリ名 必要なケース
jQuery 常に必要
jQuery UI Sortable 常に必要[1]
jquery.event.drag 常に必要
jquery.event.drop 常に必要[2]
SlickGrid用スタイルシート
ファイル名 必要なケース
slick.grid.css 常に必要
css/smoothness/jquery-ui-1.8.16.custom.css jQuery UIのスタイルを適用する場合、またはページネーション機能を要する場合
controls/slick.pager.css ページネーション機能を要する場合
SlickGridモジュール
ファイル名 必要なケース
slick.core.js 常に必要
slick.grid.js 常に必要
slick.editors.js データの編集機能を要する場合
slick.dataview.js データの表示条件を詳細に制御する必要のある場合[3]
plugins/slick.cellrangeselector.js セル選択機能を要する場合(ドラッグアンドドロップでの選択操作を可能にする)
plugins/slick.cellrangedecorator.js セル選択機能を要する場合(選択範囲を可視化する)
plugins/slick.cellselectionmodel.js セル選択機能を要する場合(データ選択範囲をプログラムから変更可能にする)
plugins/slick.cellcopymanager.js コピーアンドペースト機能を要する場合
plugins/slick.rowselectionmodel.js 行選択機能を要する場合
plugins/slick.rowmovemanager.js 行の並び替え機能を要する場合
controls/slick.pager.js ページネーション機能を要する場合
[1]公式ドキュメントではソート機能を有効化した場合のみ必要と記載されているが、他にカーソル操作での選択セル移動機能や、セルのコピーアンドペースト機能などにも使用されている。そのため、基本的には常に読み込んでおくほうが無難ではあるが、ファイルサイズが比較的大きいため、極力読み込ませずに済ませたい場合には、動作確認を充分に行うこと。
[2]公式ドキュメントでは依存ライブラリとして記載されているが、実際のところは利用されていない。よって、テストで正常に動作することが確認できれば、読み込まなくてもよい。
[3]データ表示条件を詳細に制御できる部品DataViewが利用可能になる。これによって、ページネーション、複数カラムでのソート、検索、グループ化などが可能になる。詳細は https://github.com/mleibman/SlickGrid/wiki/DataView を参照すること。

Note

ウインドウの幅に併せてテーブルの幅を変更したい場合は、SlickGridの提供機能ではないが、次のように記述して対応できる。

// (2) SlickGridの動作オプション
var options = {

  // テーブルの幅をコンテナの幅に合わせるオプションを指定
  forceFitColumns: true
};
// 画面初期化処理
$(function () {

  // (4) SlickGridテーブルを作成
  // SlickGridのインスタンスをgrid変数に格納
  var grid = new Slick.Grid('#myGrid', data, columns, options);
});
// ウィンドウサイズが変更された際に発生するイベントで、
// コンテナ幅にテーブルのサイズを合わせるメソッドを実行する処理を追加
$(window).resize(function () {
  grid.resizeCanvas();
});

ただし、ウインドウサイズを変更するたびに処理が発生するため、動作がもたつくことがある。 頻繁にウインドウサイズの変更を求められる画面では注意すること。

4.1.2. tablesorter基本構成サンプル

HTMLでは、tablesorter用のスタイルシート、依存ライブラリ、tablesorterモジュール、さらにtablesorterを有効にするために実装したJavaScriptファイル(js/default.js)を読み込む。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>tablesorter基本構成サンプル</title>

    <!-- tablesorter用のスタイルシートの読み込み -->
    <link rel="stylesheet" href="../lib/vendor/jquery.tablesorter/2.17.7/css/theme.default.css">
  </head>
  <body>

    <h1>tablesorter基本構成サンプル</h1>

    <table class="table">
      <thead>
        <tr>
          <th></th><th></th><th>年齢</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>毛利</td><td>正雄</td><td>2</td>
        </tr>
        <tr>
          <td>安田</td><td>さとみ</td><td>28</td>
        </tr>
        <tr>
          <td></td><td>文夫</td><td>45</td>
        </tr>
        <tr>
          <td>小本</td><td>里香</td><td>18</td>
        </tr>
        <tr>
          <td>中居</td><td>大輔</td><td>22</td>
        </tr>
      </tbody>
    </table>

    <!-- 依存ライブラリの読み込み -->
    <script src="../lib/vendor/jquery/1.11.1/jquery-1.11.1.min.js"></script>

    <!-- tablesorterモジュールの読み込み -->
    <script src="../lib/vendor/jquery.tablesorter/2.17.7/js/jquery.tablesorter.min.js"></script>

    <!-- 実装したJavaScriptファイルの読み込み -->
    <script src="js/default.js"></script>
  </body>
</html>

JavaScript(js/default.js)では、table要素に対し、tablesorterメソッドを実行することで、指定したテーブルにtablesorterの動作を適用する。また、tablesorterメソッドのプロパティとしてオプションを指定することで、様々な動作を実現することができる。

// default.js

'use strict';

$(function () {
  $('.table').tablesorter({

    // tablesorterの動作オプション
  });
});

Note

tablesorterには様々な依存ライブラリやスタイルシート、機能拡張用モジュールがあり、使用する機能に応じてこれらを読み込む必要がある。以下に、それぞれのファイルがどのような際に必要とされるかをまとめている(用途の少ないものは省略している)。

依存ライブラリ
依存ライブラリ名 必要なケース
jQuery 常に必須
tablesorter用スタイルシート
ファイル名 必要なケース
css/theme.default.css 常に必要
tablesorterモジュール
ファイル名 必要なケース
js/jquery.tablesorter.js 常に必要
js/widgets/widget-scroller.js ヘッダの固定を実現する場合
js/widgets/widget-editable.js データの編集機能を要する場合
addons/pager/jquery.tablesorter.pager.js ページネーション機能を要する場合

Note

基本構成サンプルではdefaut.jsを読み込んでいるが、以降の節ではそれぞれ実装したJavaScriptファイルを読み込む。

Note

SlickGridではJavaScriptでセルの値を設定するのに対し、tablesorterではHTMLに直接マークアップするのが基本的な使い方である。

この仕組みのため、tablesorterではページのロード時に、tablesorterの処理が適用前のテーブルが一時的に表示されることがある。これを防ぎたい場合は、table要素のスタイルにdisplay: noneを指定した上で、JavaScriptで $('#tablesorter').tablesorter().show() のように記述することで、tablesorterの処理が完了後に表示されるようにすればよい。

4.2. 行追加・削除・編集

4.2.1. 概要

ここでは、SlickGridおよびtablesorterを用いて、テーブルのデータ行の追加・削除を行う方法を説明する。

利用ライブラリ サンプル 参考ページ
SlickGrid SlickGridによる行追加・削除・編集サンプル SlickGrid Wiki
tablesorter tablesorterによる行追加・削除・編集サンプル

4.2.2. 利用方法

4.2.2.1. SlickGridによる行追加・削除・編集サンプル

行追加・削除・編集のためのユーザインタフェースにはいくつかのパターンが考えられるが、 この例では、次のユーザインタフェースでの実現方法を説明する。

行追加 テーブルの最下行にデータ追加用の空白行を設ける。
行削除 各行の最後のカラムにデータ削除ボタンを設ける。
データ編集
  • カーソルキーで選択セルを移動できる。
  • セル選択状態でエンターキー、またはセルのダブルクリックで編集モードに入る。
行追加・削除・編集ユーザインタフェース例

図: 行追加・削除・編集ユーザインタフェース例

SlickGrid基本構成サンプルに示したHTMLに加え、次のモジュールを読み込む。それ以外は同様なので省略する。

モジュール名 用途
slick.editors.js データの編集機能を提供する。

JavaScript(insert-and-delete-row.js)では、ユーザインタフェースの操作によって発生するイベントを監視し、行データの追加・削除を行う。

// insert-and-delete-row.js

'use strict';

(function () {

  // SlickGridのカラム定義
  var columns = [

    // (1) データのテキスト編集を可能にするため `editor` プロパティに `Slick.Editors.Text` を指定する。
    {id: 'title', name: 'Title', field: 'title', editor: Slick.Editors.Text },
    {id: 'duration', name: 'Duration', field: 'duration', editor: Slick.Editors.Text },
    {id: '%', name: '% Complete', field: 'percentComplete', editor: Slick.Editors.Text },
    {id: 'start', name: 'Start', field: 'start', editor: Slick.Editors.Text },
    {id: 'finish', name: 'Finish', field: 'finish', editor: Slick.Editors.Text },
    {id: 'effort-driven', name: 'Effort Driven', field: 'effortDriven', editor: Slick.Editors.Text },

    // (2) 削除ボタンを表示するためのカラムを定義
    {id: 'delete', name: '削除', field: '', cssClass: 'delete', width: 10,
     formatter: function () { return '<button class="delete-button">x</button>'; } }
  ];

  // SlickGrid動作オプション
  var options = {

    // (3) 編集可能にする。
    editable: true,

    // (4) セル選択時に自動的に編集モードにしない。
    autoEdit: false,

    // (5) 行追加を可能にする。
    enableAddRow: true
  };

  // 5件のサンプルデータ作成
  var data = [];
  for (var i = 0; i < 5; i++) {
    data[i] = {
      title: 'タスク ' + i,
      duration: '5 days',
      percentComplete: Math.round(Math.random() * 100),
      start: '01/01/2009',
      finish: '01/05/2009',
      effortDriven: 1
    };
  }

  function formatDate(date) {
    return ('0' + (date.getMonth() + 1)).slice(-2) + '/' +
      ('0' + date.getDate()).slice(-2) + '/' +
      date.getFullYear();
  }

  // 新規追加されるアイテムのデフォルト値
  var defaultData = {
    title: '未設定',
    duration: '未設定',
    percentComplete: 0,
    start: formatDate(new Date()),
    finish: formatDate(new Date(+new Date() + 1000 * 60 * 60 * 24)),
    effortDriven: 'false'
  };

  // 画面初期化処理
  $(function () {

    // SlickGridテーブルを作成
    var grid = new Slick.Grid('#myGrid', data, columns, options);

    // (6) クリックイベントハンドラ
    grid.onClick.subscribe(function (e, args) {
      if ($(e.target).hasClass('delete-button')) {
        data.splice(args.row, 1);
        grid.invalidate();
      }
    });

    // (7) 行追加イベントハンドラ
    grid.onAddNewRow.subscribe(function (e, args) {

      // 追加されたアイテムにデフォルト値を設定してデータに追加し、更新する。
      var item = $.extend({}, defaultData, args.item);
      data.push(item);
      grid.updateRowCount();
      grid.invalidateRow(data.length - 1);
      grid.render();
    });
  });

}());

行追加機能は、ソースコードリスト上の(5)・(7)で実現している。 (5)でオプションenableAddRowtrueにすることで、最下行にデータ追加用の空白行が表示されるようになり、 空白行に新たなデータが入力された際にonAddNewRowイベントが発生するようになる。このイベントを(7)で監視し、 空白行へ追加されたデータをdataに追加して、テーブルを再描画している。

行削除機能は、(2)・(6)で実現している。 (2)のカラム定義ではformatterプロパティにHTML文字列を返す関数を指定して、delete-buttonクラスを持つ 行削除用ボタンを作成している。このようにformatterプロパティに任意の文字列を返す関数を指定することで、 該当するカラムの各セル内にレンダリングされるHTMLを変更できる。 またテーブルがクリックされた際に発生するonClickイベントを(6)で監視し、 もしクリックされた要素が(2)で作成したdelete-buttonクラスを持つボタンであれば、クリックされた行のデータを dataから削除して、テーブルを再描画している。

データ編集機能は、(1)・(3)・(4)で実現している。 (1)のカラム定義ではeditorプロパティにテキスト編集を可能にするSlick.Editors.Text[4]を指定し、 (3)でオプションeditabletrueにすることで、セルのデータ編集が可能になる。 またカーソルキーで選択セルを移動できるようにするため、(4)でオプションautoEditfalseにして セル選択時に自動的に編集モードに入らないようにしている。

[4]テキスト編集をするSlick.Editors.Text以外にも、数値を編集するSlick.Editors.Integer、日付を編集するSlick.Editors.Dateなどの編集用オブジェクトが提供されている。ただしドキュメントが整備されていないため、何が利用できるかはslick.editors.jsのソースコードを参照する必要がある。

Note

SlickGridでは、データの追加や削除などを画面に反映するためにinvalidateおよびrenderなどのメソッドを実行する必要がある。 その際に使用するメソッドを以下に示す。

SlickGridの主なメソッド
メソッド名 説明
grid.render() 再描画対象になっている行を再描画する。再描画対象を設定するにはinvalidateRowなどのメソッドを使用する。
grid.invalidateRow(Number) 特定行を再描画対象にする。引数には行インデックス番号(0から開始)を示す数値を与える。
grid.invalidateRows(Array<Number>) 複数の特定行を再描画対象にする。引数には行インデックス番号(0から開始)を示す数値の配列を与える。
grid.invalidateAllRows() 全ての行を再描画対象にする。
grid.invalidate() すべての行を再描画する。renderメソッドを実行しなくても再描画される。

4.2.2.2. tablesorterによる行追加・削除・編集サンプル

この例では、次のユーザインタフェースを設けることで実現する方法を説明する。

行追加 ボタンクリックで、テーブルの最下行にデータを追加する。
行削除 各行の最後のカラムにデータ削除ボタンを設ける。
データ編集 セルをクリックすると編集モードに入る。
行追加・削除・編集ユーザインタフェース例

図: 行追加・削除・編集ユーザインタフェース例

tablesorter基本構成サンプルで示したHTMLに加え、次のモジュールを読み込む。

モジュール名 用途
widget-scroller.js データの編集機能を提供する。

また、各データ行に削除ボタンを用意する。以下に該当箇所を抜粋する。

    <!-- tablesorterを使用するテーブル -->
    <table id="tablesorter">
      <thead>
        <tr><th></th><th></th><th>年齢</th><th>削除</th></tr>
      </thead>
      <tbody>
        <tr><td><div>毛利</div></td><td><div>正雄</div></td><td><div>28</div></td><td><button class="remove-btn">x</button></td></tr>
        <tr><td><div>安田</div></td><td><div>さとみ</div></td><td><div>28</div></td><td><button class="remove-btn">x</button></td></tr>
        <tr><td><div></div></td><td><div>文夫</div></td><td><div>45</div></td><td><button class="remove-btn">x</button></td></tr>
        <tr><td><div>小本</div></td><td><div>里香</div></td><td><div>18</div></td><td><button class="remove-btn">x</button></td></tr>
        <tr><td><div>中居</div></td><td><div>大輔</div></td><td><div>23</div></td><td><button class="remove-btn">x</button></td></tr>
        <tr><td><div>木久</div></td><td><div>なみ</div></td><td><div>28</div></td><td><button class="remove-btn">x</button></td></tr>
        <tr><td><div>大西</div></td><td><div>昌子</div></td><td><div>31</div></td><td><button class="remove-btn">x</button></td></tr>
        <tr><td><div>岩佐</div></td><td><div>純子</div></td><td><div>45</div></td><td><button class="remove-btn">x</button></td></tr>
        <tr><td><div>清水</div></td><td><div>一久</div></td><td><div>19</div></td><td><button class="remove-btn">x</button></td></tr>
        <tr><td><div>山峰</div></td><td><div>行紀</div></td><td><div>63</div></td><td><button class="remove-btn">x</button></td></tr>
      </tbody>
    </table>

JavaScript(insert-and-delete-row.js)では、ユーザインタフェースの操作から行データの追加・削除・編集を行う。

/* jshint camelcase: false */
/* eslint camelcase: 0 */
// insert-and-delete-row.js

'use strict';

$(function () {

  // テーブルにtablesorterを適用する。
  var $tablesorter = $('#tablesorter').tablesorter({

    // (1)編集機能の設定
    widgets: ['editable'],
    widgetOptions: {

      // 編集可能なカラムを設定
      editable_columns: [0, 1, 2],

      // 編集後にEnterキー押下で編集完了とする。
      editable_enterToAccept: true,

      // 編集後の自動ソートを無効にする。
      editable_autoResort: false
    }
  });

  // 行の追加ボタンのイベント
  $('#add-btn').on('click', function () {
    var age = parseInt(Math.random() * 100);
    var row = '<tr><td><div>姓</div></td><td><div>名</div></td><td><div>' + age +
          '</div></td><td><button class="remove-btn">X</button></td>';
    var $row = $(row);

    // テーブルに行を追加する。
    $tablesorter.find('tbody').append($row);

    // (2)追加した行をtablesorterに認識させる。
    $tablesorter.trigger('addRows', [$row, false, function () {

      // (3)追加した行を修正可能にする。
      $tablesorter.trigger('refreshWidgets', true);
    }]);
  });

  // 行の削除ボタンのイベント
  $('table').on('click', 'button.remove-btn', function () {

    // テーブルから行の削除
    $(this).closest('tr').remove();

    // (4)データの削除をtablesorterに認識させる。
    $tablesorter.trigger('update');
  });
});

行追加機能は、 データ行のtr要素をテーブルのtbodyに追加した後、ソースコードリスト上の(2)でaddRowsイベントを発生させることで、行が追加されたことをtablesorterに認識させる。

行削除機能は、 テーブルのtbodyから データ行のtrを削除した後、ソースコードリスト上の(4)でupdateイベントを発生させることで、行が削除されたことをtablesorterに認識させる。

データ編集機能は、ソースコードリスト上の(1)・(3)で実現している。 (1)でwidgetsの配列に'editable'を追加することで、データ編集機能の利用が可能になる。また、widgetOptionsで編集時の動作を設定している。 (3)では、後から追加された行も編集可能とするためにrefreshWidgetsイベントを発生させている。ただしこの処理は行追加が終わった後に実行される必要があるため、(2)のコールバック関数として指定している。

Note

tablesorterはデータ編集を実現するために、contentEditable属性を用いているが、Internet ExplorerではcontentEditable属性をtd要素へ設定することができない。 そのため、セルの値をcontentEditable属性を設定できるdiv要素やspan要素内に記述する必要がある。 なお、このサンプルではdiv要素を用いて実装している。

Note

tablesorterでは、データの追加や削除などを行った後、それらの状態変化をtablesorterに認識させる必要がある。その際に発生させるイベント名を以下に示す。

なお、tablesorterの公式リファレンスでは、これらの手動で発生させるイベントのことを method と表現しているため、参照する際は注意すること。本ガイドラインでもこれにならって メソッド と表現する。

tablesorterの主なメソッド
メソッド名 説明
addRows 行を追加する際に実行する。tablesorterがキャッシュしているテーブル情報を更新する。
update 行の削除する際に実行する。tablesorterがキャッシュしているテーブル情報を更新する。
refreshWidgets 設定されているウィジェットを削除し、再設定する際に実行する。

4.3. 行の並び替え

4.3.1. 概要

ここでは、SlickGridを用いて、行の並び替えを行う方法を説明する。

利用ライブラリ サンプル 参考ページ
SlickGrid SlickGridによる行の並び替えサンプル SlickGrid Wiki

4.3.2. 利用方法

行の並び替えをするためには、SlickGridに関連付けられたデータ配列の中身を並び替えてテーブルを再描画すればよい。 概念的にはシンプルだが、複数行の一括並び替えなどを実現する場合は、並び替えの処理に複雑な実装が必要となる。

この例では、次のユーザインタフェースでの実現方法を説明する。

  • 行ドラッグアンドドロップ操作による並び替えができる
  • Ctrl または Shift クリックで複数行を選択して一括で並び替えができる

SlickGrid基本構成サンプルで示したHTMLに加え、次のモジュールを読み込む。それ以外は同様なので省略する。

モジュール名 用途
slick.editors.js 行のドラッグアンドドロップ操作ができるユーザインタフェースを提供する
slick.rowselectionmodel.js 行選択機能を提供する

JavaScript(move-row.js)では、ユーザインタフェースの操作によって発生するイベントを監視し、行データの並び替えとテーブルの再描画を行う。

// move-row.js

'use strict';

(function () {

  // SlickGridのカラム定義
  var columns = [

    // (1) 行ドラッグアンドドロップ機能を有効化するため、すべてのカラムに `behavior: 'selectAndMove'` を設定する。
    {id: 'title', name: 'Title', behavior: 'selectAndMove', field: 'title'},
    {id: 'duration', name: 'Duration', behavior: 'selectAndMove', field: 'duration'},
    {id: '%', name: '% Complete', behavior: 'selectAndMove', field: 'percentComplete'},
    {id: 'start', name: 'Start', behavior: 'selectAndMove', field: 'start'},
    {id: 'finish', name: 'Finish', behavior: 'selectAndMove', field: 'finish'},
    {id: 'effort-driven', name: 'Effort Driven', behavior: 'selectAndMove', field: 'effortDriven'}
  ];

  // SlickGridの動作オプション
  var options = {

    // 何も指定しない。
  };

  // 1000件のサンプルデータ作成
  var data = [];
  for (var i = 0; i < 1000; i++) {
    data[i] = {
      title: 'タスク ' + i,
      duration: '5 days',
      percentComplete: Math.round(Math.random() * 100),
      start: '01/01/2009',
      finish: '01/05/2009',
      effortDriven: (i % 5 === 0) ? 'true' : 'false'
    };
  }

  // 画面初期化処理
  $(function () {

    // SlickGridテーブルを作成
    var grid = new Slick.Grid('#myGrid', data, columns, options);

    // (2) 行選択機能のプラグインを追加
    grid.setSelectionModel(new Slick.RowSelectionModel());

    // (3) 行ドラッグアンドドロップ移動機能のプラグインを追加
    var moveRowsPlugin = new Slick.RowMoveManager();
    grid.registerPlugin(moveRowsPlugin);

    // (4) 行ドラッグアンドドロップイベントハンドラ
    //     移動操作を受けた行を、移動先の位置に挿入して並び替える処理を実装する。
    moveRowsPlugin.onMoveRows.subscribe(function (e, args) {

      var i,

          // 移動操作を受けた行のインデックス番号
          rows = args.rows,

          // 移動先の行のインデックス番号
          insertBefore = args.insertBefore;

      var left = data.slice(0, insertBefore);
      var right = data.slice(insertBefore, data.length);

      // 複数行選択時の選択順を、行のインデックス番号の小さい順でソート
      var extractedRows = [];
      rows.sort(function (a, b) { return a - b; });
      for (i = 0; i < rows.length; i++) {
        extractedRows.push(data[rows[i]]);
      }

      // データ全体のソート
      rows.reverse();
      for (i = 0; i < rows.length; i++) {
        var row = rows[i];
        if (row < insertBefore) {
          left.splice(row, 1);
        } else {
          right.splice(row - insertBefore, 1);
        }
      }
      data = left.concat(extractedRows.concat(right));

      // 選択状態を復元
      var selectedRows = [];
      for (i = 0; i < rows.length; i++) {
        selectedRows.push(left.length + i);
      }

      // データと画面を更新する。
      grid.resetActiveCell();
      grid.setData(data);
      grid.setSelectedRows(selectedRows);
      grid.render();
      grid.invalidate();
    });
  });

}());

行のドラッグアンドドロップ操作は、ソースコードリスト上の(1)・(3)・(4)で実現している。 (3)でドラッグアンドドロップ操作を実現するプラグインをテーブルにセットした上で、(1)のカラム定義で behaviorプロパティに'selectAndMove'を設定する。 これによりドロップアンドドロップ操作が可能となり、また操作後にはonMoveRowsイベントが発生するようになる。 このイベントを(4)で監視し、コールバック関数内でデータの並び替えと再描画を行っている。

複数行の一括並び替え機能は、(2)・(4)で実現している。 (2)では行選択機能を提供するプラグインをテーブルにセットしている。 (4)ではデータ配列を並び替えてテーブルを再描画している。 並び替えの処理は、複数行の一括の並び替えなど、様々な操作条件に対応するため複雑な実装になっているが、 SlickGridの使用方法の説明という目的から外れるため、この部分の説明は割愛する。

Note

このサンプルでは、複数行を選択して一括で並び替えを行う操作(1行目と4行目を選択し、2行目に移動するなど)を実現しているが、並び替えのロジックはライブラリから提供されていない。ライブラリが提供しているのは、「複数行の選択状態を管理する機能」と「ドラッグアンドドロップ操作によりイベントを発生させる機能」であり、これらの機能と独自実装した並び替えのロジックを組み合せて実現している。

この他にも、SlickGridはロジックの独自実装に活用できるインタフェースや独自イベントを提供していることから、フレームワークとしての性質が強い。

4.4. ヘッダを固定したデータ行のスクロール

4.4.1. 概要

ここでは、SlickGrid、tablesorterを用いてヘッダを固定してデータ行をスクロールする実装方法を説明する。

利用ライブラリ サンプル 参考ページ
SlickGrid SlickGridによるヘッダを固定したデータ行のスクロールサンプル SlickGrid Wiki
tablesorter tablesorterによるヘッダを固定したデータ行のスクロールサンプル jQuery plugin: Tablesorter 2.0 - Scroller Widget

4.4.2. 利用方法

4.4.2.1. SlickGridによるヘッダを固定したデータ行のスクロール

SlickGridは標準でヘッダが固定されるため、特別な考慮は不要である。よってSlickGrid基本構成サンプルを参照すること。

4.4.2.2. tablesorterによるヘッダを固定したデータ行のスクロール

tablesorter基本構成サンプルで示したHTMLに加え、次のモジュールを読み込む。それ以外は同様なので省略する。

モジュール名 用途
widget-scroller.js ヘッダ固定機能を提供する。

JavaScript(fixed-header.js)では、テーブル要素に対しtablesorterメソッドを実行する。ヘッダのthead要素を固定するためにはtablesorterメソッドのオプションであるwidgets配列に'scroller'を追加する。

/* jshint camelcase: false */
/* eslint camelcase: 0 */
// fixed-header.js

'use strict';

$(function () {

  // ヘッダを固定するテーブルに対し、tablesorterメソッドを実行する。
  // その際、widgetsプロパティに['scroller']を設定する。
  $('#tablesorter').tablesorter({
    widgets: ['scroller'],
    widgetOptions: {

      // テーブルの髙さの指定
      scroller_height : 200
    }
  });
});

widgetOptionsプロパティでテーブル要素の高さを設定できるscroller_heightなどオプションが提供されている。これらの詳細について知りたい場合は、 tablesorterの公式ウェブサイトのリファレンス を参照すること。

4.6. ソート

4.6.1. 概要

ここでは、SlickGridおよびtablesorterを用いて、テーブルのデータのソートを行う方法を説明する。

利用ライブラリ サンプル 参考ページ
SlickGrid SlickGridによるソートサンプル SlickGrid Wiki
tablesorter tablesorterによるソートサンプル jQuery plugin: Tablesorter 2.0 - Scroller Widget

4.6.2. 利用方法

4.6.2.1. SlickGridによるソート

HTMLはSlickGrid基本構成サンプルで説明した基本構成と同様なので、省略する。

JavaScript(sort.js)では、ヘッダのクリック操作からソートイベントを発生させ、ソート処理を実行する。

// sort.js

'use strict';

(function () {
  var i, len;

  // SlickGridのカラム定義
  var columns = [

    // (1) ソート機能を有効化するカラム定義に `sortable: true` を設定する。
    {id: 'id', name: 'ID', field: 'id', sortable: true},
    {id: 'value1', name: 'value 1', field: 'value1', sortable: true},
    {id: 'value2', name: 'value 2', field: 'value2', sortable: true},
    {id: 'value3', name: 'value 3', field: 'value3', sortable: true}
  ];

  // SlickGridの動作オプション
  var options = {

    // 何も指定しない。
  };

  // 1000件のサンプルデータ作成
  var data = [];
  for (i = 0; i < 1000; i++) {
    data[i] = {
      id: 'タスク' + i,
      value1: Math.round(Math.random() * 100),
      value2: Math.round(Math.random() * 1000),
      value3: Math.round(Math.random() * 10000)
    };
  }

  // ソート関数を定義
  // 文字列の場合は文字列比較を、数値の場合は数値比較をした結果でソートする。
  function sortfn(o1, o2) {
    if (o1[column.field] > o2[column.field]) {
      return 1;
    } else if (o1[column.field] < o2[column.field]) {
      return -1;
    }
    return 0;
  }

  // (2) `data` を基にソート用インデックス `indicies` を作成
  //     データ表示時はこのインデックスを経由してデータを引き当てるようにしている。
  var indices = {};
  var column;
  for (i = 0, len = columns.length; i < len; i++) {
    column = columns[i];
    indices[column.id] = [];
    data.sort(sortfn);
    for (var j = 0; j < data.length; j++) {
      indices[column.id][j] = data[j];
    }
  }

  // 画面初期化処理
  $(function () {

    // ソート設定を保持する変数
    var isAsc = true;                  // 初期設定は昇順
    var currentSortCol = { id: 'id'};  // 初期設定は id カラムでソート

    // (3) データ引き当て関数。`Slick.Grid` コンストラクタの引数で使用
    //     ソート用インデックス `indices` を経由して表示データを引き当てる。
    function getItem(index) {
      var newIndex = isAsc ? index : data.length - index - 1;
      return indices[currentSortCol.id][newIndex];
    }

    // データ長取得関数。`Slick.Grid` コンストラクタの引数で使用
    // テーブルに表示するデータの長さは変更しないため、 ``data`` の長さを返す。
    function getLength() {
      return data.length;
    }

    // (4) SlickGridテーブルを作成
    //     第2引数に配列を指定する代わりに、 `getLength` および `getItem` 関数を持つオブジェクトを指定して
    //     ソート設定に基づきデータの表示を行う。
    var grid = new Slick.Grid('#myGrid', {getLength: getLength, getItem: getItem}, columns, options);

    // (5) ソートイベントハンドラ
    grid.onSort.subscribe(function (e, args) {

      // ソート設定を書き換える。
      isAsc = args.sortAsc;
      currentSortCol = args.sortCol;

      // テーブル全体を再描画
      grid.invalidateAllRows();
      grid.render();
    });
  });

}());

ソート機能の実現は、ユーザインタフェース部とデータ表示ルール変更部から成り立つ。

ユーザインタフェース部は、ソースコードリスト上の(1)・(5)で実現している。 (1)でカラム定義のオプションsortabletrueにすることで、ヘッダがクリックされた際にスタイルの変更や onSortイベントが発生するようになる。このイベントを(5)で監視し、クリックされたヘッダのカラムを基に ソート設定を書き換え、テーブル全体を再描画している。

データ表示ルール変更部は、(2)・(3)・(4)で実現している。 (4)で示すように、Slick.Gridコンストラクタの第2引数に、データの配列の代わりにgetLengthgetItem関数を持つオブジェクトを指定している。こうすることで、テーブルの各行にはgetItem関数の返すデータが表示されるようになる。

getItem関数は(3)で定義している。引数indexは表示行のインデックス番号を受け取るので、これを用いて、 あらかじめ(2)で作成しておいたインデックスからソート設定に基づいてデータを引き当てている。

Note

この例では、ソートのためのインデックス作成とデータ引き当てについて複雑な実装を行っている。 これはパフォーマンスを考慮したためである。

最もシンプルな実装は、onSortイベントハンドラ内で、 クリックされたカラムの値をもとにdata配列を 逆順ソートすることである。この実装の場合、データ長が数千件ならよいが、数万件以上に及んだ場合には ソートを実行する度に大きなオーバーヘッドが発生する。

SlickGridの主要な用途の一つに大量データ表示が挙げられるため、ここでは大量データ表示に耐えうる ソートの実装を例示した。

4.6.2.2. tablesorterによるソート

tablesorterは標準でデータのソートが可能なため、特別な考慮は不要である。よって tablesorter基本構成サンプル を参照すること。

なお、tablesorterは、デフォルトの設定で数値か文字かを自動的に判別しソートできる。 また、複合キーによるソートが可能であり、Shiftキーを押した状態でのソートの操作、またはJavaScriptの実装により、実現できる。 詳細はtablesorterの公式ウェブサイトのリファレンスを参照すること。

Note

標準で提供されているソート機能を無効化したい場合は、無効化したいカラムのth要素に対して、data-sorter=falseの属性を設定する。

4.7. カラムの並び替え

SlickGridは標準でカラムの並び替えができるため、特別な考慮は不要である。よってSlickGrid基本構成サンプルを参照すること。

Note

標準で提供されているカラムの並び替え機能を無効化するためには、動作オプションenableColumnReorderfalseに設定する。

4.8. コピーアンドペースト編集

4.8.1. 概要

ここでは、SlickGridを用いて、テーブルのデータのコピーアンドペーストによる編集を行う方法を説明する。

利用ライブラリ サンプル 参考ページ
SlickGrid SlickGridによるコピーアンドペースト編集サンプル SlickGrid Wiki

4.8.2. 利用方法

SlickGrid基本構成サンプルで示したHTMLに加え、次のモジュールを読み込む。それ以外は同様なので省略する。

モジュール名 用途
slick.cellcopymanager.js コピーアンドペースト機能を提供する
slick.cellrangeselector.js セル選択機能を提供する
slick.cellrangedecorator.js セル選択機能を提供する
slick.cellselectionmodel.js セル選択機能を提供する

JavaScript(copy-and-paste.js)では、コピーアンドペースト操作によって発生するイベントを監視し、データのコピーとテーブルの再描画を行う。

// copy-and-paste.js

'use strict';

(function () {

  // SlickGridのカラム定義
  var columns = [
    {id: 'num', name: '', field: 'id', width: 30},
    {id: 'title', name: 'Title', field: 'title'},
    {id: 'duration', name: 'Duration', field: 'duration'},
    {id: '%', name: '% Complete', field: 'percentComplete'},
    {id: 'start', name: 'Start', field: 'start'},
    {id: 'finish', name: 'Finish', field: 'finish'},
    {id: 'effort-driven', name: 'Effort Driven', field: 'effortDriven'}
  ];

  // SlickGrid動作オプション
  var options = {

    // 何も指定しない。
  };

  // 1000件のサンプルデータ作成
  var data = [];
  for (var i = 0; i < 1000; i++) {
    data[i] = {
      id: i,
      title: 'タスク ' + i,
      duration: '5 days',
      percentComplete: Math.round(Math.random() * 100),
      start: '01/01/2009',
      finish: '01/05/2009',
      effortDriven: (i % 5 === 0) ? 'true' : 'false'
    };
  }

  // 画面初期化処理
  $(function () {

    // SlickGridテーブルを作成
    var grid = new Slick.Grid('#myGrid', data, columns, options);

    // (1) セル選択機能のプラグインを追加
    var cellSelectionModel = new Slick.CellSelectionModel();
    grid.setSelectionModel(cellSelectionModel);

    // (2) コピーアンドペースト機能のプラグインを追加
    var copyManager = new Slick.CellCopyManager();
    grid.registerPlugin(copyManager);

    // (3) ペーストイベントハンドラ
    copyManager.onPasteCells.subscribe(function (e, args) {
      var from = args.from[0];
      var to = args.to[0];
      var i, I, j, J;

      // コピー元のデータを保存するための配列
      var src = [];

      // コピー元のデータを保存
      for (i = 0, I = from.toRow - from.fromRow; i <= I; i++) {
        src[i] = [];
        for (j = 0, J = from.toCell - from.fromCell; j <= J; j++) {
          src[i][j] = data[from.fromRow + i][columns[from.fromCell + j].field];
        }
      }

      // ペースト先にコピーしたデータを上書き
      for (i = 0, I = src.length; i < I && (i + to.toRow) < data.length; i++) {
        for (j = 0, J = src[i].length; j < J && (j + to.toCell) < columns.length; j++) {
          data[to.fromRow + i][columns[to.fromCell + j].field] = src[i][j];
          grid.invalidateRow(to.fromRow + i);
        }
      }

      // ペースト先を選択状態にする。
      cellSelectionModel.setSelectedRanges([{
        fromRow: to.fromRow,
        fromCell: to.fromCell,
        toRow: to.fromRow + i - 1,
        toCell: to.fromCell + j - 1
      }]);

      grid.render();
    });
  });

}());

ソースコードリスト上の(1)で、セル選択機能を提供するプラグインを設定している。また(2)でコピーアンドペースト機能を提供するプラグインを設定している。これによってコピーアンドペースト操作によってonPasteCellsイベントが発生するようになるため、これを(3)で監視し、データのコピー後、テーブルの表示を更新している。

4.9. テーブルのスクロールによる非同期データ取得

4.9.1. 概要

ここでは、SlickGridを用いて非同期通信でデータを取得し、テーブルに表示する方法を紹介する。

検索画面などで大量データをテーブルに表示する場合、全データを1度に表示するとクライアントやサーバに負荷が掛かる。そのため、初期表示に必要な分だけデータを取得し、以降はユーザー操作に合わせて非同期通信で取得するのが望ましい。

上記を実現するには、スクロール時に非同期通信でデータを取得し、SlickGridに関連付けられたデータ配列に追加してテーブルを再描画すればよい。概念的にはシンプルだが、非同期通信が頻発しないようある程度の件数をまとめて取得するなど、独自に作りこむ必要がある。

利用ライブラリ サンプル 参考ページ
SlickGrid SlickGridによる非同期データ取得サンプル SlickGrid Wiki

サンプルの動作イメージを示す。 下図は、初期表示時のテーブルを示している。

初期表示時の表示範囲と取得範囲

図: 初期表示時の表示範囲と取得範囲

前提として、本例ではテーブルの領域を以下に分類する。

領域 説明
表示範囲 テーブルのうち、画面に表示される範囲を示す。本例では20件とする。
取得範囲 1度の非同期通信で取得する範囲を示す。本例では50件とする。

初期表示時は、取得範囲のデータを非同期通信で取得し、表示範囲のデータを画面に表示する。

次に、スクロール後のイメージを示す。

スクロール後の表示範囲と取得範囲

図: スクロール後の表示範囲と取得範囲

スクロールによって表示範囲が取得範囲からはみ出している。この時点で次の取得範囲分のデータを非同期通信で取得する。

Note

表示範囲の件数はテーブルの高さに依存する。高さを広げる場合、初期表示時にテーブルが空行にならないよう取得範囲を調整すること。

また、取得範囲の件数が表示範囲に近いほど、非同期通信の頻度が高まる。システムの要件などを考慮し、取得範囲の件数を調整すること。

4.9.2. 利用方法

SlickGridを利用した非同期データ取得の実装例を紹介する。

SlickGrid基本構成サンプルに示したHTMLに加え、独自に実装した次のモジュールを読み込む。それ以外は同様なので省略する。

JavaScriptは以下を実装する。

モジュール名 用途
slickgrid-with-ajax.js スクロールを監視し、非同期通信を行う関数を実行する。また、テーブルを描画する。
slickgrid-remotemodel.js 非同期通信でデータを取得する。

各JavaScriptの実装を説明する。

slickgrid-with-ajax.jsの実装を以下に示す。 なお、SlickGridのカラム定義、SlickGrid動作オプションは SlickGrid基本構成サンプルのJavaScript(js/default.js)と同一であるため、省略する。

// slickgrid-with-ajax.js

'use strict';

(function () {

  $(function () {

    // SlickGridのカラム定義
    /* omitted */

    // SlickGrid動作オプション
    /* omitted */

    var grid;
    var loadingIndicator = null;

    // テーブルデータを非同期で取得するオブジェクト生成
    var loader = new Slickgrid.Data.RemoteModel();

    // 画面初期化処理
    $(function () {

      // SlickGridテーブルを作成
      grid = new Slick.Grid('#myGrid', loader.data, columns, options);

      // スクロール時に起動するイベント
      grid.onViewportChanged.subscribe(function () {

        // 開始位置・終了位置取得
        var vp = grid.getViewport();

        // データ取得関数実行
        loader.ensureData(vp.top, vp.bottom);
      });

      // ローディング中に起動するイベント
      loader.onDataLoading.subscribe(function () {

        // データ取得中であることを示すメッセージ出力
        if (!loadingIndicator) {
          loadingIndicator = $('<span><label>Buffering...</label></span>')
            .appendTo(document.body);

          // CSSの設定
          /* omitted */
        }
        loadingIndicator.show();
      });

      // ローディング後に起動するイベント
      loader.onDataLoaded.subscribe(function (e, args) {

        // 表示する行のみ有効化
        for (var i = args.from; i <= args.to; i++) {
          grid.invalidateRow(i);
        }
        grid.render();
        loadingIndicator.fadeOut();
      });

      // テーブル表示
      grid.onViewportChanged.notify();
    });
  });

}());

slickgrid-with-ajax.jsには3つのイベントを実装する。各イベントの機能は以下の通り。

イベント名 説明
onViewportChanged スクロール時に発生する。テーブルの表示領域をgrid.getViewportで取得する。
onDataLoading 非同期通信中に発生する。データ取得中であることを示すインディケータを表示する。
onDataLoaded 非同期通信後に発生する。grid.invalidateRowで再描画対象を設定し、grid.renderでテーブルを再描画する。完了後にインディケータを非表示にする。

次に、slickgrid-remotemodel.jsを説明する。 なお、ソースが長いため、途中で区切って解説を加える。

// slickgrid-remotemodel.js

'use strict';

(function () {
  function RemoteModel() {

    // 変数定義
    var PAGESIZE = 50;
    var data = {
      length : 1000
    };

PAGESIZEは取得範囲の件数である。表示範囲の開始位置・終了位置をPAGESIZEで除算することで、取得範囲上の位置(以降、ポインタとする)を得られる。また、非同期通信で取得するデータの件数などにも使用する。

dataはテーブルデータを格納する。

var hRequest = null;
var req = null;

// イベント
var onDataLoading = new Slick.Event();
var onDataLoaded = new Slick.Event();

function init() {
}

// データ取得関数
function ensureData(from, to) {

  // 非同期通信が実行中の場合、直前の処理を中断する
  if (req) {
    req.abort();
    for (var i = req.fromPage; i <= req.toPage; i++) {

      // 処理中のデータを削除する
      data[i * PAGESIZE] = null;
    }
  }

  // 開始位置が0以下の場合は0に補正する
  if (from < 0) {
    from = 0;
  }

  // 終了位置が上限以上の場合は上限値に補正する
  if (data.length > 0) {
    to = Math.min(to, data.length - 1);
  }

  // 開始位置・終了位置からポインタを算出する
  var fromPage = Math.floor(from / PAGESIZE);
  var toPage = Math.floor(to / PAGESIZE);

パラメータのfromtoには、テーブル表示の開始位置・終了位置が格納されいている。 PAGESIZEで除算することでポインタを取得する。

// ポインタが異なる場合、位置を補正する
while (!(data[fromPage * PAGESIZE] === null || data[fromPage * PAGESIZE] === undefined) &&
  fromPage < toPage) {
  fromPage++;
}

while (!(data[toPage * PAGESIZE] === null || data[toPage * PAGESIZE] === undefined) &&
  fromPage < toPage) {
  toPage--;
}

スクロールによって表示範囲が取得範囲を跨った場合、ポインタを前後に補正する。

例えばテーブルを下方向にスクロールし、表示範囲がテーブルデータの40件目から60件目にある場合、開始位置のポインタは「0」、終了位置のポインタは「1」となる。

上記の場合はfromPageを加算し、後続の判定でポインタ「1」(テーブルデータの50件目から100件目の範囲)にデータが存在するかチェックする。

// 取得範囲のデータが取得済みか判定する
if (fromPage > toPage ||
  (fromPage === toPage && !(data[fromPage * PAGESIZE] === null || data[fromPage *
    PAGESIZE] === undefined))) {

  // テーブルを再描画するイベントを発生させる
  onDataLoaded.notify({
    from : from,
    to : to
  });
  return;
}

データの有無をチェックし、存在する場合はテーブルを再描画する。

// 非同期通信のURLを編集する
var url = 'js/slickgrid-data.json';

非同期通信に使用するURLを編集する。

Note

本例ではurlを固定としている。サーバからデータを取得する場合は、データを絞り込むために開始位置や取得件数などをパラメータとして設定する。以下に例を示す。

var url = "http://your.server.path/scroll?start=" + (fromPage * PAGESIZE) + "&limit=" + PAGESIZE);
  // setTimeoutが実行中の場合、直前の処理を中断する
  if (hRequest !== null) {
    clearTimeout(hRequest);
  }

  // 非同期通信を実行する
  hRequest = setTimeout(function () {

    // データ取得中であることを示すイベントを発生させる
    onDataLoading.notify();

    // 非同期通信処理
    req = $.ajax({
      type : 'GET',
      url : url,
      dataType : 'json'
    }).done(function (data) {

      // データ配列を編集する
      onSuccess(data, fromPage);
    });

    // 中断時にデータを削除するために格納する
    req.fromPage = fromPage;
    req.toPage = toPage;
  }, 100);
}

スクロールはマウスホイールによって連続的に実行される可能性があるため、setTimeoutで一定時間待機後に非同期通信を実行する。

    // データ編集を行う関数
    function onSuccess(resp, fromPage) {
      var from = fromPage * PAGESIZE, to = from + resp.results.length;

      // 取得したデータをdataに格納する
      for (var i = 0; i < resp.results.length; i++) {
        var item = resp.results[i].item;

        data[from + i] = item;
        data[from + i].index = from + i;
      }

      req = null;

      // テーブルを再描画するイベントを発生させる
      onDataLoaded.notify({
        from : from,
        to : to
      });
    }

    init();

    return {

      // プロパティ
      'data' : data,

      // 関数
      'ensureData' : ensureData,

      // イベント
      'onDataLoading' : onDataLoading,
      'onDataLoaded' : onDataLoaded
    };
  }

  // Slick.Data.RemoteModel
  $.extend(true, window, {
    Slick : {
      Data : {
        RemoteModel : RemoteModel
      }
    }
  });
}());

最後に取得したデータをdataに格納し、テーブルを再描画する。

Note

本例ではテーブルの表示件数を1000件に固定している。必要に応じてdata.lengthに任意の数値を設定すること。

Note

本例ではデータの変動(追加・変更・削除)を考慮していない。取得したデータはクライアント側でキャッシュするため、サーバ側でデータが変動すると齟齬が生じる。非同期通信時にクライアント・サーバ間のデータをチェックするなど、変動を前提とした実装を考慮すること。