【DataTables】独自の検索機能を追加する

Webサービスを構築する際に、通常のサービスとは別に管理画面が必要になる場合があります。

管理画面は利用者が限られていますので、派手でインタラクティブである必要はありません。
しかし、使いやすく見やすい管理画面は、本サービスとは違うベクトルで作るのが大変です。

時間がない場合、管理画面に必要な機能がパッケージされたライブラリを使うという選択肢があります。
色々なライブラリがありますが、最近私が使用したのはAdminLTEです。

adminlte.io

AdminLTEのメリットは別の機会で触れるとして、
AdminLTEでは、テーブル操作をするためにDataTablesを使用しています。

datatables.net

このライブラリは、テーブル操作に必要なソートや検索がデフォルトでついています。
WebAPIとの非同期通信にも対応している使い勝手の良いライブラリです。
デフォルトでも十分ですが機能拡張も出来ます。

今回は、DataTablesを拡張して独自の検索をできるようにする方法について触れます。

今回実装する要件

日付毎に集計されたデータがあるとします。
集計されたデータから、日付の範囲を指定して検索できるようにします。

See the Pen DataTables CustomField by shibainu (@websandbag) on CodePen.


日付の指定は直接入力ではなく、カレンダーのポップアップから選択できるようにします。

使用するライブラリ

DatablesはjQueryのライブラリですので下記は必ず使用します。

任意で必要なライブラリ

上記の他に使用するライブラリは下記です。 必ず使用する必要はありませんので、要件に合わせて変えてください。

  • Date Range Picker:カレンダーから年月日を指定できるようにする
  • momentjs:日時の比較をしたり、Data Range Pickerで使用
  • bootstrap 4:簡単にテーブルの見た目を綺麗にする

また、DataTablesはbootstrap用のライブラリを公開しています。
bootstrapのバージョンによって読み込むファイルも変わりますので合わせて選択してください。

cdn.datatables.net

基本的な実装部分

まずは、DataTableでテーブルを構築します。
tableタグに対してDataTableを実行するようにすれば次のようなテーブルが作られます。

f:id:nakahashi_h:20200115195606p:plain

ソース

HTML

<div class="container-fluid mt-3">
    <table class="table" id="my_table">
        <thead>
            <tr>
                <th scope="col">日付</th>
                <th scope="col">作業</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>2020/1/1</td>
                <td>作業1</td>
            </tr>
            <tr>
                <td>2020/1/2</td>
                <td>作業2</td>
            </tr>
            <tr>
                <td>2020/1/3</td>
                <td>作業3</td>
            </tr>
            <tr>
                <td>2020/1/4</td>
                <td>作業4</td>
            </tr>
            <tr>
                <td>2020/1/5</td>
                <td>作業5</td>
            </tr>
        </tbody>
    </table>
</div>

javascript

テーブル用のタグにDataTableを実行します。

$(document).ready(function(){
  $('#my_table').DataTable({
    'language': {
      'url': "//cdn.datatables.net/plug-ins/3cfcc339e89/i18n/Japanese.json"
    },
    'pagingType': 'full_numbers',
    'iDisplayLength': 10
  })
})

今回は日本語に対応させますので、languageオプションに日本語用のファイルを使うようにしています。

独自の検索をフィールドを追加する

次に日付検索用のフィールドを追加します。
DataTablesが用意しているフィールドとは別になりますので、わかりやすい場所にタグを追加します。

<div class="container-fluid mt-3">
    <div class="container-fluid mt-3">
        <div class="row" id="custom_filters">
            <div class="col-sm-12"><label>開始日:<input class="custom_filter table-between form-control form-control-sm" id="between--start"/></label></div>
            <div class="col-sm-12"><label>終了日:<input class="custom_filter table-between form-control form-control-sm" id="between--end"/></label></div>
        </div>
    </div>

独自検索の実装

次に、期間の検索処理とカレンダーから年月日を選択できる機能を追加します。

独自検索のルールを追加

独自の検索は、jQueryのライブラリを拡張する事で実装できます。
独自のルールを実装する場合は、$.fn.dataTable.ext.search.pushで検索用の関数を追加します。

datatables.net

$.fn.dataTable.ext.search.push(function(settings, data, dataIndex){
 
  // 検索フィールドの要素を取得して、momentの形式に置き換えます。
  let start = $('#between--start').val()
    ? moment($('#between--start').val())
    : null
  let end = $('#between--end').val()
    ? moment($('#between--end').val())
    : null
    
  // 日付を取得して、momentの形式に置き換えます。 
  // 最初の列の要素なので、0を指定します。   
  let target = moment(data[0]);
  
  // 日付を比較して条件に合えばtrueを返します。 
  // trueを返す事で検索結果に表示出来ます。
  if((! start || target.isSameOrAfter(start))
    && (! end || target.isSameOrBefore(end))
  ){
      return true;
  }
  return false;
})

追加された関数は、テーブルの行毎に実行されます。
引数のdataに列毎のデータが入っていますので、列番号を指定して該当のデータを取得する事で比較ができます。

カレンダーの実装

Data Range Pickerを実装し、検索フィールドをクリックするとカレンダーのポップアップが出るようにします。

このライブラリは時間の検索も出来ますが、今回は日付のみです。
オプションのsingleDatePickerを有効にします。

$(document).ready(function(){
  let $myTable = $('#my_table').DataTable({
    // 省略
    // DataTableの要素読み込み完了後に実行されます。
    'initComplete': function (settings, json){
      // 検索フィールドに、Data Range Pickerのカレンダーを追加します。
      let $pickerFormat = 'YYYY/MM/DD'
      let $tableBetween = $('.table-between')
      $tableBetween. daterangepicker({
        timePicker: false,
        singleDatePicker: true,
        autoUpdateInput: false,    // 空欄を許可する場合はautoUpdateInputをFalseにします。
        locale: {
          format: $pickerFormat
        }
      }).on('apply.daterangepicker', function(ev, picker){
        // カレンダーから日付を選んだ時に実行されます。 
        $(this).val(picker.startDate.format($pickerFormat))
        $myTable.draw();
      }).on('hide.daterangepicker', function(ev, picker){
        // カレンダーが閉じた場合に実行します。未選択でカレンダーが閉じられた場合のためです
        if(! $(this).val()) {
          $myTable.draw();
        }
      });
    }
  })
})

DataTablesとの連携は、draw()で行います。
実行する事で、テーブルを再描画して検索結果を反映します。

datatables.net

自由検索窓の排除

範囲指定のみ行いたい場合は、デフォルトでついている自由検索窓が不要です。
そのため、検索窓から除外します。

レイアウトを変える場合は、sDomオプションで指定します。

legacy.datatables.net

ページングや表示件数等の要素を独自のdivで内包する事が出来ます。
他のタグは使えませんので、独自のタグを挿入したい場合はjsでDomを操作するなどの方法で行います。

bootstrap4の場合

自由検索だけ省いた状態で出力するには次のような指定をします。

$(document).ready(function(){
  let $myTable = $('#my_table').DataTable({
    'sDom': '<"row"<"col-sm-12"lr>><"row"t><"row"<"col-sm-12 col-md-5"i><"col-sm-12 col-md-7"p>>',

検索の設定値の保持

要件によっては、前回の検索ワードや設定をそのまま残しておきたい場合があります。
DataTablesでは入力値の保存機能は実装されています。

保持機能を有効にする

DataTablesのstateSaveオプションを有効にする事で入力値を保持できるようになります。
自由検索や表示件数のようなデフォルト機能の設定は、stateSaveを有効にするだけで対応できます。

$(document).ready(function(){
  let $myTable = $('#my_table').DataTable({
    'stateSave': true,

独自設定を保持する

今回追加したような独自の検索フィールドは対象ではありません。
独自の検索結果の場合はDataTablesを拡張して保持できるようにします。

入力値を保持する

保持時のコールバック関数にfnStateSaveParamsが用意されています。
この関数を使う事で、保持時に処理を追加することができます。

datatables.net

コールバックの関数では、引数に保持用の変数をつける事ができます。
その引数は配列なので、任意のキーと値を挿入する事で一緒に保持します。

今回は、inputタグに付与したname属性をキーにします。

$(document).ready(function(){
  let $myTable = $('#my_table').DataTable({
    // 省略
    'fnStateSaveParams': function (oSettings, oData) {
      $customFilters.each(function () {
        if($(this).attr('name')) {
          oData[$(this).attr('name')] = $(this).val().replace('"', '"');
        }
      });
      return oData;
    }
前のセッションで保持した値を初期値に代入する

ブラウザを更新した時、前項で保持した値をフィールドの初期値に代入します。
DataTablesで入力された値を呼び出す時のコールバック関数にfnStateLoadParamsが用意されています。

legacy.datatables.net
(fnStateLoadParamsの項を参照してください。)

前項でname属性をキーにして保存したため、キーと入力フィールド名を照合してvalue属性に代入します。

$(document).ready(function(){
  let $myTable = $('#my_table').DataTable({
    // 省略
    'fnStateLoadParams': function (oSettings, oData) {
      $customFilters.each(function () {
        let $customFilter = $(this);
        $.each(oData, function(index, value){
          if(index == $customFilter.attr('name')) {
            $customFilter.val(value);
          }
        })
        return true;
      });
    }
参考

flynsarmy.com


以上です。

デフォルトでも十分使えるライブラリですが、案件の目的に合わせてカスタマイズする事が出来ます。
管理画面だけでなく、いろいろの用途でも使えますので是非ご検討ください。

©︎2017-2018 WebSandBag