【Laravel】DataTablesを使う(jQuery)

もくじ

DataTablesとは

簡単にテーブルを実現できるDataTablesをご存知でしょうか。

datatables.net

HTMLの<table>タグでソートや検索機能を追加するための jQueryプラグインです。

しかし大量のデータを扱うにはあまり向きません。実験したところ1000件でパフォーマンスが結構落ちます。10000件にもなると表示するだけで結構時間がかかります。

もし大量のデータを扱いたい時はjsonにするとパフォーマンスが向上します。

詳しくはこの記事をご参照ください。

bonoponz.hatenablog.com

DataTablesを設置する準備(Laravelに導入)

今回はDataTablesをLaravelで使ってみようと思います。CDNのパターンとダウンロードして使うパターンがあります。

なお前提として、bootstrap4とjQuerycssとscriptを導入している必要があります。

くわしくは↓

bonoponz.hatenablog.com

CDN

bootstrap4も同時に利用するので、それも使えるように合わせて設置します。すでにbootstrap4を導入していても、DataTables用のリンクがあるので必要になります。

bladeに以下のコードを適切な箇所に挿入します。

<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.21/css/jquery.dataTables.min.css"/>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.21/css/dataTables.bootstrap4.min.css"/>
<script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.10.21/datatables.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.21/js/dataTables.bootstrap4.min.js"></script>

最新のcdnアドレスは公式サイトから確認してください。

bootstrap4を使うための最新のcdnアドレスは公式サイトから。

ダウンロード

公式サイトから必要項目を選択しファイルをダウンロードします。

Step 1 、 Step 2 、 Extensionsを必要なものを選択します。

最後にStep 3の「Download」タブからダウンロードできます。

MinifyとConcatenateのチェックは好きにして問題ありません。

Minifyにチェックをするとminファイルになります。

ConcatenateにチェックをするとStep 1、Step 2、Extensionsで選んだ項目が一つにまとめられます。チェックしなければ、それぞれ別のファイルをしてダウンロードできます。

これでDataTablesを使う準備は整いました。次は実際にDataTablesのテーブルを表示しましょう。

DataTablesを挿入

テーブル設置

わかりやすいようにbladeをわけます。新しくdatatables.blade.phpを作成します。

touch ./resources/views/datatables.blade.php

DataTablesを反映する前にまず通常のテーブルを設置します。

<table class="table">
  <thead>
    <tr>
      <th scope="col">name</th>
      <th scope="col">sex</th>
      <th scope="col">age</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Wada</td>
      <td>Male</td>
      <td>35</td>  
    </tr>
    <tr>
      <td>Sugiyama</td>
      <td>Male</td>
      <td>20</td>  
    </tr>
    <tr>
      <td>Fukui</td>
      <td>Female</td>
      <td>49</td>  
    </tr>
  </tbody>
</table>

テーブルが設置されました!

DataTablesの反映

先ほど設置したテーブルにidを付加します。

<table id="example" class="table"> // 変更
  <thead>

<script>タグを追加します。

<script>
$(document).ready(function() {
    $('#example').DataTable();
});
</script>

DataTablesが反映されました! 検索ボックスやページングなども初期から設置されています。

Controllerから配列を渡してforeachする

さきほどと比較しやすいように、配列のデータをひとつ増やします。

$data = [
  [
    'name' => 'Wada',
    'sex' => 'Male',
    'age' => 35,
  ],
  [
    'name' => 'Sugiyama',
    'sex' => 'Male',
    'age' => 20,
  ],
  [
    'name' => 'Fukui',
    'sex' => 'Female',
    'age' => 49,
  ],
  [
    'name' => 'Ono',
    'sex' => 'Female',
    'age' => 33,
  ]
];

return view('datatables',[
  'data' => $data,
]);
<tbody>
  @foreach ($data as $value)
    <tr>
      <td>{{ $value['name'] }}</td>
      <td>{{ $value['sex'] }}</td>
      <td>{{ $value['age'] }}</td>  
    </tr>
  @endforeach
</tbody>

Controllerから配列を渡せました。このとき、デフォルトで一列目がソートされています。

インデックス番号を使ってソート

インデックス番号の詳しい使い方は↓こちら。

bonoponz.hatenablog.com

<table id="example" class="table">
  <thead>
    <tr>
      <th scope="col">No</th> // 追加
      <th scope="col">name</th>
      <th scope="col">sex</th>
      <th scope="col">age</th>
    </tr>
  </thead>
<tbody>
  @foreach ($data as $key => $value) // 変更
    <tr>
      <td>{{ $key }}</td> // 追加
      <td>{{ $value['name'] }}</td>
      <td>{{ $value['sex'] }}</td>
      <td>{{ $value['age'] }}</td>  
    </tr>
  @endforeach
</tbody>
</table>

デフォルトで一列目がソートされます。なので、インデックス番号でソートする時は一列目にNoを配置します。

そうするとインデックス番号でソートされるので、配列の順番のままで表示されます。

オプション

オプションでいろいろ設定すると、ソートする列を指定したり、日本語化したり、好きにカスタマイズできます。

注意点(カンマを忘れずに)

詳しく説明する前に、注意点を先に述べておきます。

$('#example').DataTable({
  data: json,
  columns: [
    {data: 'ID'},
    {data: 'name'},
    {data: 'sex'},
    {data: 'age'},
  ],
  columnDefs: [
    { targets: 0, visible: false },
    { targets: 'ageColumn', width: 40 },
  ],
  order: [ [ 3, "desc" ] ],
});

このように複数のオプションを指定する際、それぞれの指定のあとにはカンマを忘れずに記述して区切りましょう。

lengthChange(表示件数選択機能)

ページングが有効な時、1ページで何件表示するかを設定できるプルダウンです。これを非表示にします。

$('#example').DataTable({
  lengthChange: false,
});

消えました。

searching(検索機能)

テーブルの中身を検索できるボックスです。これを非表示にします。

$('#example').DataTable({
  searching: false,
});

消えました。

order(ソート機能)

指定した列を昇順または降順でソートできます。

orderを使って[ [ 列番号, 昇順降順 ], ... ]の形式で指定します。

列番号が0は1列目です。ascが昇順、descが降順となります。

今回は年齢を降順でソートします。なので、年齢は4列目なので列番号3を、降順なのでdescを指定します。

$('#example').DataTable({
  order: [ [ 3, "desc" ] ],
});

年齢列で降順になりました。

iDisplayLength(初期表示件数指定)

ページを表示したときに、初めに何件表示するかを指定できます。

仮データを増やして試してみます。

まず指定しないと初期値では10件をはじめに表示してくれます。

24件中10件ずつ表示されているのがわかります。これを1ページで20件ずつに指定します。

$('#example').DataTable({
  iDisplayLength: 20,
});

24件中20件ずつに変更されました。

language(日本語化)

初めは英語表記ですが、日本語に変更できます。

日本語にするだけでなく、自己流に変更も可能です。

jsonを読み込む

CDNで日本語化されたjsonを読み込みます。

$('#example').DataTable({
  language: {
            url: "http://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/Japanese.json"
        } 
});

最新はこちらCDNから。

日本語になりました。

自己流にアレンジ

$('#example').DataTable({
  language: {
    "decimal": ".",
    "emptyTable":     "表示するデータがありません。",
    "thousands": ",",
    "sProcessing": "処理中...",
    "sLengthMenu": "_MENU_ 件表示",
    "sZeroRecords": "データはありません。",
    "sInfo": " _TOTAL_ 件中 _START_ から _END_ まで表示",
    "sInfoEmpty": " 0 件中 0 から 0 まで表示",
    "sInfoFiltered": "(全 _MAX_ 件より抽出)",
    "sInfoPostFix": "",
    "sSearch": "検索:",
    "sUrl": "",
    "oPaginate": {
      "sFirst": "先頭",
      "sPrevious": "前",
      "sNext": "次",
      "sLast": "最終"
    }
  },
});

初期値では、jsonを読み込んだときと同じです。日本語の部分を自己流に変更することでアレンジできます。

columns(カラム設定)

公式ドキュメント(columns)

列固有の初期化プロパティを設定します。

個々の列の動作に関する詳細を定義できますが、テーブルにあるすべての列の配列にエントリが必要です(オプションを指定しない場合は、nullにすることができます)。

"columns": [
    { "searchable": false },
    null,
    null
  ]

上記は、最初の列のフィルタリングを無効にし、3列のセルがあることがわかります。

配列やjsonを読み込んでいる場合は、dataにキー名を指定します。dataについてはこちら→columns.data

columns: [
  {data: 'ID' },
  {data: 'name' },
  {
    bSortable: false,
    data: null,
    sDefaultContent:'',
  },
],

上記の場合、1列目にID、2列目にname、を表示するように指定しています。そして3列目はbSortable: falseでソートを無効にし、jsonに無いデータをあてたいときdataはnullとしセルの存在を指定します。

sDefaultContentオプションはイベントが割り当てられている単純な編集ボタンなどの静的コンテンツを列に入れたい場合で使用できます。このオプションは、JSONのセル値がnullであることが判明した場合にここで設定された値が使用されるため、JSONデータのロード時に役立ちます。

各列にclassを付与('21 3月更新)

生成された列に対して、個別にclassを追加したいこともあります。それもとても簡単です。

columns: [
  { data: 'No' },
  { data : 'name', className: 'userName' },
  { data: 'body' }
],

結果として以下のようになります。

<td>No</td>
<td class="userName">名前</td>
<td>本文</td>

カラムデータの結合('21 1月更新)

上のようにnameカラムとageカラムを別々に表示しています。

これを結合して下のようにひとつのカラムにできます。

では実際に書いてみましょう。

<table id="exampleTable" class="table hover nowrap">
  <thead>
    <tr>
      <th scope="col">ID</th>
      <th scope="col">name(age)</th>
      <th scope="col">sex</th>
    </tr>
  </thead>
</table>

〜(略)〜

<script>
$(function() {
  const json = @json($res)

  function getNameAndAge(data, type, dataToSet) {
    return data.name + "(" + data.age + ")";
  }

  $('#exampleTable').DataTable({
    data: json,
    columns: 
      [
        {data: 'ID'},
        { data: getNameAndAge },
        {data: 'sex'},
      ],
  });
});
</script>

今回はgetNameAndAgeというメソッドを作成し、name(age)のように結合して表示させています。

戻り値を好きなように加工してみましょう。

XSS対策('20 12月更新)

そのままデータを追加するとサニタイズされないのでXSSが成立してしまいます。XSS対策のため、render$.fn.dataTable.render.text()を設定しておきましょう。

columns: [
        { data: "ID" },
        { data: "name",  render: $.fn.dataTable.render.text() },
        { data: "title",  render: $.fn.dataTable.render.text() },
        { data: "body",  render: $.fn.dataTable.render.text() },
        ...
    ]

ユーザに入力された値を持つカラムに設定しておけばいいと思います。

仮にこのIDが自動採番のカラムであれば入力された値ではないのでXSS対策をする必要はありません。

columnDefs(特定のカラム設定)

公式ドキュメント(columnDefs)

特定の列にだけスタイル・プロパティを適用したい時はcolumnDefsを使います。columnsオプションと異なり、すべての列を指定する必要はありません。ただし、columnsオプションと同じような設定ができます。

列の幅変更

幅を指定したい列に、classを設けます。

<tr>
  <th scope="col">ID</th>
  <th scope="col">name</th>
  <th scope="col">sex</th>
  <th scope="col" class="ageColumn">age</th>
</tr>

jQueryで幅を指定します。targetsで列のclassを指定。widthに幅を指定。

$('#example').DataTable({
  columnDefs: [
    { 
        targets: 'ageColumn',
        width: 40
     },
  ],
});

小さい数値にしておくと、最低幅になります。

もしセル内で折り返し(改行)をしたくない場合、テーブルのclassにnowrapを指定すれば解決します。

<table id="example" class="table nowrap">

中央揃え-センタリング('21 1月更新)

columnDefsでどのカラムかを指定するためにクラスを設定します。

<tr>
  <th scope="col">ID</th>
  <th scope="col" class="centeringColumn">name</th>
  <th scope="col">sex</th>
  <th scope="col">age</th>
</tr>

次に、jQuery側でtargetsclassを指定し、classNameを追加します。

$('#example').DataTable({
  columnDefs: [
    { 
        targets: 'centeringColumn',  // どの列か指定
        width: 40,
        className : 'dt-body-center dt-head-center'  // センタリングの指定
     },
  ],
});

今回はheaderとbodyともにセンタリングしました。ヘッダーだけをセンタリングしたりも可能です。下表のとおりです。

中央揃えにしたい場所 付与するクラス
<thead> dt-head-center
<tbody> dt-body-center
headerとbody両方 dt-head-center
dt-body-center

参考URL;Datatables コピペでOK、スクロールするテーブルを簡単設置

指定した列を非表示に

$('#example').DataTable({
  columnDefs: [
    {
        targets: 0,
        visible: false 
    },
  ],
});

targetsで数値を指定するときは、列番号になります。

1列目が0、2列目が1のように順に増えます。右側からの列を指定したい場合は右から1列目が-1、右から2列目は-2のようになります。

visiblefalseにすることで非表示になります。この場合、非表示になるだけで列は存在はするので、別のプロパティで列を指定する際に、この列も数える必要があります。

これでID欄が非表示になりました。

ソート可否指定

特定のカラムだけソート機能を無効にしたい場合に使用できます。

"columnDefs": [ 
{
  "targets": 0,
  "searchable": false,
},

参考URL

公式サイト

DataTablesの使い方 - Qiita

jQuery DataTablesを使うときのXSS対策 - Qiita