【JavaScript】DataTablesが超便利すぎる

# DataTablesとは

DataTablesは、HTMLテーブルを対話的なデータグリッドに変換するためのJavaScriptライブラリ。
簡単に言い換えると、HTMLテーブルをソートや検索などがおこなえる高機能な表にできるということ。
**拡張性** や **柔軟性** が高く、また大規模なデータを持つテーブルを操作するのにとても便利である。

# 導入

下記のリンクから自分の環境に合ったやり方でダウンロードしよう。また、基本的に　**jQuery** は必須である。

https://datatables.net/download/

# 最もシンプルな例

とりあえず簡単な実装例を挙げてみる。
ここでは理解できなくてもOK！

<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="html,result" data-slug-hash="PoyrNwW" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/PoyrNwW">
  DataTables</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# 使い方

これからDataTablesの使い方を説明していく。

最初は以下のcssとjsファイルだけでOK! (CDN以外の書き方は割愛)

```js
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet"/> 
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
```

## テーブルの作成

idがappの要素のHTMLテーブルをdataTableにする。
<details><summary>sample.html(クリックすると表示)</summary><div>

```js:sample.html
<table id="app">
  <thead>
    <tr>
      <th>Id</th>
      <th>Name</th>
      <th>City</th>
      <th>age</th>
    </tr>
    <tr>
      <td>1</td>
      <td>Taro</td>
      <td>Tokyo</td>
      <td>18</td>
    </tr>
  </thead>
</table>
```

</div></details>

```js:sample.js
// テーブルの作成
$("#app").DataTable();
```

これだけでDataTableができる。
しかし、これだと表のスタイルが変わっただけで、何もできない。

`DataTable()`の引数にオプションを指定できる。
このオプションを設定することによって、ソートや検索が可能になるのだ！

## オプションの設定

以下のように設定する。

```js:sample.js
// オプションの設定
var tableOptions = {
    // ここに設定値を書いていく
}

// テーブルの作成
$("#app").DataTable(tableOptions);
```

テーブルのオプションはとてもたくさんある。

https://datatables.net/reference/option/

この記事では代表的なものだけ説明する。

### data

htmlにテーブルを書くと長くなるのでjsで配列にして、それをdataに設定できる。

```js:sample.js
// テーブルの中身
var tableData = [
  [1, "Taro", "Tokyo",12],
  [2, "Jiro", "Osaka", 20],
  [3, "Hanako", "Paris", 18],
  [4, "Alice", "New York",26],
  [5, "Bob", "London",24]
];
// オプションの設定
var tableOptions = {
  // テーブルの内身を設定
  "data": tableData,
}
$("#app").DataTable(tableOptions);
```

### info

テーブルの下にShowing ~とテーブル情報が出てくる。

```js
var tableOptions = {
  "info": false,
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/276f7a57-397b-f2a7-8932-f8722fe0a1be.png)
### paging
ページング処理を追加する。

```js
var tableOptions = {
  "paging": false,
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/f012f4e4-08c1-498c-bc3f-631d92f2acc7.png)

### searching

検索窓を追加する。

```js
var tableOptions = {
  "searching": true,
}
```

:::note warn
searchingをfalseにすると独自のカスタムフィルタもoffになってしまう。検索窓だけ非表示にする場合は、cssに以下を追記しよう。
```css:sample.css
.dataTables_filter {
    display: none;
}
```
:::

### ordering

ソート機能が追加できる

```js
var tableOptions = {
  "ordering": false,
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/170457af-fa6d-081d-4483-1e97b9508a2c.png)

### dom

テーブルの表示に関連する要素の配置をカスタマイズするために使用。

* l : テーブルの左側に表示される要素（デフォルトの検索ボックスなど）
* f : フィルタ
* t : テーブルそのもの
* i : テーブルの情報表示（現在の表示中の行数など）
* p : ページングコントロール
* r : テーブルの右側に表示される要素（デフォルトの凡例など）
* B : Buttons(extention)

### ajax 

Ajax通信を行う際のurlとHTTPメソッドを指定する。

```js
var tableOptions = {
  "ajax": {
    "url": "data.json",
    "type": "POST"
  }
}
```

### serverSide

dataTableの処理をサーバーサイドで行う。

1. 初期化時には、空のデータテーブルが表示
1. ページング、ソート、検索などのアクションが実行されると、サーバーサイドにAjaxリクエストが送信される。
1. サーバーサイドはリクエストを受け取り、必要なデータを取得・処理する。
1. サーバーサイドは処理結果をレスポンスとして返す。
1. データテーブルはサーバーからのレスポンスを受け取り、表示データを更新。

serverSideオプションを使用すると、データテーブルはクライアントサイドではなくサーバーサイドでデータの処理を行うため、大量のデータや複雑な処理にも対応可能。

```js
var tableOptions = {
    "serverSide" : true,
    "ajax": {
      url: 'data.php',
      type: 'POST'
    }
}
```

### columnDefs

ターゲットに列のインデックスかセレクタを指定し、その列に対しての動作を設定する。
`target : '_all'`とすると、すべての列が対象となる。cssの設定やソートの禁止、カラムの非表示、特定のレンダリング関数の適用などができる。

```js
var tableOptions = {
  "columnDefs": [
    { targets: 0, visible: false },  // インデックス0(1列目)の列を非表示
    { targets: [1, 2], sortable: false }, // インデックス1と2の列をソート禁止
    // 全ての列にCSSクラス 'highlight' を適用
    { targets: '_all', className: 'highlight' }, 
    // インデックス3と4の列に数値をフォーマット
    { targets: [3, 4], render: $.fn.dataTable.render.number(',', '.', 2, '$') }
  ]
}
```
### order

dataTableのデフォルトのソート順を指定する。
`order:[[column, dir]]`のようにするcolumnに列のインデックス、dirにはasc（昇順）またはdesc（降順）を指定できます。

```js
var tableOptions = {
  "order": [
    [0, 'asc'],
  ]
}
```

### select

trueにすると行を選択できるようになる

```js
var tableOptions = {
    "select" : true
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/5e89e163-7545-38b5-da78-3b0b17d66e8e.png)

:::note 
selectは拡張機能の１つなので、以下をダウンロードする必要がある
https://cdn.datatables.net/select/1.6.2/css/select.dataTables.min.css
https://cdn.datatables.net/select/1.6.2/js/dataTables.select.min.js
:::


### initComplete

DataTableの初期化が完了した後に実行したい追加の関数を指定する。
コールバック関数には、settings, json, xhrの３つのパラメータが渡される。

* settings : 初期化されたデータテーブルの設定オブジェクト
* json : 初期化時に取得されたデータのJSON
* xhr : 初期化時に使用されたXMLHttpRequestオブジェクト

```js
var tableOptions = {
  "initComplete": function(settings, json, xhr) {
    // 初期化完了時の処理をここに記述する
    console.log('データテーブルの初期化が完了しました');
    console.log('設定オブジェクト:', settings);
    console.log('取得したデータ:', json);
  }
}
```


### displayLength

表示する行数を指定する。デフォルトでは、10行が表示される。

```js
var tableOptions = {
    "paging": true,
    "displayLength": 25,
}
```

### lengthMenu

表示行数の選択肢を指定する。ドロップダウンメニューで変更できる

```js
var tableOptions = {
    "paging": true,
    "displayLength": 10,
    "lengthMenu": [10, 100,1000]
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/9cd54aef-6664-609e-cb7f-8500f72156b0.png)

### lengthChange

```js
var tableOptions = {
    displayLength: 25,
    lengthMenu: [10, 25, 50, 100]
}
```

### destroy

DataTableを初期化するときに、指定されたセレクタに一致する既存のDataTableがある場合、そのテーブルは破棄され、新しいテーブルに置き換える。

```js
var tableOptions = {
    destroy: true,
}
```

### pagingType

ページングのスタイルと動作を設定できる。
デフォルトは`"simple_numbers"`
```js
var tableOptions = {
    'displayLength': 25,
    'lengthMenu': [10, 25, 50, 100],
    'pagingType': pagingType,
}
```

| Paging Type           | 説明                                                     |
|-----------------------|-------------------------------------------------------|
| simple                | Previous, Nextのボタンのみ表示                               |
| simple_numbers        | Previous, Nextのボタンに加えてページ番号も表示               |
| full                  | First, Last, Previous, Nextのボタンを表示                    |
| full_numbers          | First, Last, Previous, Nextのボタンに加えてページ番号も表示  |
| first_last_numbers    | First, Last, Previous, Nextのボタンに加えてページ番号も表示  |

### drawCallback

テーブルが描画された後に実行されるコールバック関数を指定する。

:::note
**initCompleteとdrawCallbackの違い**
initCompleteは初期化後１回だけ実行されるのに対して、drawCallbackは再描画されるごとに実行される。
:::

### processing

processingオプションをtrueに設定すると、テーブルが処理中のときに「処理中です」と表示を行う。主にサーバーとの通信を行うときに使われる。

```js
var tableOptions = {
    processing: true,
}
```

## API

DataTableのAPIを使えば、テーブルを操作することができる。

APIへのアクセスは何個かあるが

```js
// 全部同じ
$( selector ).DataTable(); //　推奨。もっとも新しい。
$( selector ).dataTable().api();
new $.fn.dataTable.Api( selector );
```

:::note warn
\\$(selector).DataTable();と$(selector).dataTable();は違うことに注意しよう。前者はdatatableのapiインスタンスを返すのに対し、後者はjQueryオブジェクトを返す。また、dataTable()は古いv.1.9以前の書き方で、1.10以降はDataTable()の書くのが主流。ただし、dataTableの場合fnDestroy()だが、DataTable()で作成した場合はDestroy()になる。
その他にもfnDraw()、fnSettings() などがdraw(), settings()に対応する。
:::

APIも非常にたくさんあるので、この記事では代表的なものだけ説明する。

https://datatables.net/reference/api/


### 再描画

**draw()** を使う。

```js
var table = $('#sample').DataTable(); // 以後省略
table.draw();
```

### テーブルデータの削除

**clear()** を使う。テーブルの中身がヘッダー以外削除される。

```js
//　削除して再描画
table.clear().draw();
```
### ソート

**order()** を使用。

```js
table.order([[1, 'asc']]).draw();
```

### ページ変更

`page()`を使う。引数には数字以外にfirst, last, previous, nextが使用可能。
再描画を防ぐために`draw(false)`を付ける。

```js
// 3ページ目を表示
table.page(2).draw( false );
```

### データの取得

```js
var data = table.data();
console.log(data);
```

### テーブルの削除

`destroy()`を使う。

```js
table.destroy()
```

### 列操作

#### 列表示/非表示
`column(number).visible(bool);`を使用。　

```js
// 3列目を非表示にする
table.column(2).visible(false);
```

#### 全列表示/非表示

`table.columns().visible(bool);`を使えば全列削除できる。


### 行操作

#### 行追加

`row.add()` で追加できる。

```js
table.row.add( {
     ...
    } ).draw();
```

#### 行削除

```js
table.row( $(this).parents('tr') )
     .remove()
     .draw();
```

## カスタムDOMイベント

DataTablesによるイベントは、on('event', callback)メソッドを使用して監視することができる。DataTablesのイベントは名前空間が **dt** となる。

```js
$('#sample').on('draw.dt', function() {
  // テーブルが再描画されたときに実行する処理
});
```

また、offを使うとonによって登録されたイベントを削除できる。

```js
// 特定のリスナー(callback)を解除
$('#sample').off('draw.dt', callback);
```

他にもテーブルのソート、検索など色々検知することができる。
これもたくさんあるので、公式ドキュメントを見てください。

https://datatables.net/reference/event/


## buttons

https://datatables.net/reference/button/

buttonsを使う場合は [Buttons extension](https://datatables.net/extensions/buttons/)をダウンロードしよう。

では、以下を追加してください(CDN)。

```html
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet"/>
<link href="https://cdn.datatables.net/buttons/2.3.6/css/buttons.dataTables.min.css" rel="stylesheet"/>
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/2.5.0/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.colVis.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.print.min.js"></script>
```

### buttonsの使用例

buttonsを使うとExcel、 CSV、 PDF出力、印刷、Copyのボタンが簡単に実装できる。

<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="html,result" data-slug-hash="YzJoopr" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/YzJoopr">
  Untitled</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### シンプルなボタン

まず、DataTablesのオプションの `"dom"` に **B** を含める。
そして、`"buttons"オプション`に以下のように追加したいボタンを追加しよう。

```js
// オプションの設定
var tableOptions = {
  'dom': 'Bfrtip',
  'buttons': [
        'pdf,
        'csv',
    ],
}
```

ボタンにはcsv, excel, pdf, copy, print, colvis (column visibility) などがある。

他の種類は公式ドキュメントにのっている。

https://datatables.net/reference/button/

### カスタムボタン

もちろんボタンはカスタムすることができる。
以下はカスタマイズされたCSVボタンの例である。

```js
// オプションの設定
var tableOptions = {
    dom: 'Bfrtip',
    buttons: [{
        extend: 'csv', // 出力フォーマットの指定
        filename: 'test', // 出力ファイル名の指定
        text: 'CSV出力', // ボタンの表示名
        exportOptions: {
            paging: false, //
        },
    }],
}
```

#### extend

出力フォーマットを指定する。

```js
buttons: [{
    extend: 'csv'
}]
```
#### filename

出力ファイル名を指定する。

```js
buttons: [{
    filename: 'test'
}]
```

#### text

ボタンに表示される名前を指定する。

```js
buttons: [{
    text: 'CSV出力',
}]
```

#### exportOptions

* modifier : エクスポートするデータに対して修正を加えるオプションを設定。出力時にもソート結果や検索結果, pagingを反映するかを指定できる。
    - order : appliedにするとソートが反映される。
    - page : currentにすると現在のページのみ出力される。(暗黙的にorderとsearchがappliedになる。
    - search : appliedにすると検索結果のみ出力される。
  
 ```js
exportOptions : {
    modifier: {
        "order":  'current',  // 'current', 'applied', 'index',  'original'
        "page":   'all',      // 'all',     'current'  
        "search": 'none',     // 'none',    'applied', 'removed'
        // Extension - KeyTable (v2.1+) - cells only
        focused: undefined, // true, false, undefined
        // Extension - Select (v1.0+)
        selected: undefined // true, false, undefined
    }
}
```

* columns : エクスポートに含める特定の列を指定する
* rows : エクスポートに含める特定の行を指定する

#### action

ボタンをクリックしたときの処理を書く。
関数の引数には**e**, **dt**, **node**, **config**がある。

* e : イベントオブジェクト。
* dt : datatableのapiインスタンス。データテーブルを操作できる。
* node : クリックしたボタンの要素。ボタンの外観や動作を変更できる。
* config : ボタンの設定オブジェクト。ボタンの設定を動的に変更できる。

```js
buttons: [{
    text: 'Alert',
    action: function ( e, dt, node, config ) {
        alert( 'Activated!' );
        this.disable(); // ボタンを非表示にする
    }
}]
```

#### customize

ボタンの外観や動作をカスタマイズするための関数を指定する。

```js
buttons: [{
    customize: function (win) {
        $(win.document.body).find('table').addClass('display').css('font-size', '9px');
        $(win.document.body).find('h1').css('text-align','center');
    }
}]
```

# さらなる高みへ

## 拡張機能

ここまででもbuttonsやselectなど少し触れたが、datatableではいくか拡張機能が用意されている。拡張機能を使うには新たなjsとcssが必要となる。

https://datatables.net/extensions/index


| 拡張機能          | 説明                                                                                      |
|-------------------|-------------------------------------------------------------------------------------------|
| AutoFill          | ユーザーが入力したデータを自動的に他のセルにコピーするためのインタラクティブな機能。              |
| Buttons           | ファイル出力やコピーなどのボタンを提供し、データテーブル上でさまざまなアクションを実行できる。   |
| ColReorder        | 列の順序をドラッグアンドドロップで変更できる。                      |
| Editor            | インライン編集や追加、削除などのデータの編集を容易にする機能。             |
| FixedColumns      | スクロール可能なデータテーブルの固定列を作成できる。                 |
| FixedHeader       | データテーブルのヘッダー行を固定して表示し、スクロールしても表示され続けるようにする機能。       |
| KeyTable          | キーボード操作でセルを選択できるようにする機能。                    |
| Responsive        | データテーブルをレスポンシブなレイアウトに対応させる機能。          |
| RowGroup          | データテーブルの行をグループ化し、グループの集計や表示切り替えなどの操作をサポートする機能。  |
| RowReorder        | 行の順序をDrag & Dropで変更できる。               |
| Scroller          | 大量のデータを含むデータテーブルをスクロール可能にする機能。         |
| Select            | 行やセルの選択を可能にし、選択されたデータの操作やハイライト表示をサポートする機能。   |
| SearchPanes       | データテーブルの検索機能を強化し、絞り込みオプションを提供する機能。          |
| SearchBuilder     | 複雑な検索条件をビジュアルに作成し、データテーブルの検索を強化する機能。|
|StateRestore       | 表の状態をsaveすることができる。|
| DateTime          | 日付と時刻のフィルタリングと表示を簡素化する機能。 |

## plugins

プラグインを使えば、API, Paging, Sortingなどの機能を強化できる。

https://datatables.net/plug-ins/index

たとえば、以下の例では **paginType** に **scrolling** というオプションを追加している。

```html
<script type="text/javascript" src="jquery.dataTables.js"></script>
<script type="text/javascript" src="dataTables.scrollingPagination.js"></script>
<script type="text/javascript">
    $(document).ready(function() {
        $('#example').dataTable( {
            "pagingType": "scrolling"
        } );
    } );
</script>
```

## サーバサイドとの連携

### django-datatables-view

Pythonには[django-datatables-view](https://pypi.org/project/django-datatables-view/)というDjangoフレームワークで使用するための拡張機能がある。
django-datatables-viewを使用すると、データテーブルの表示やデータの取得などの処理をサーバーサイドで行うことができる。

### djangorestframework-datatables

同じく、Djangoのrestframeworkの拡張機能で、[djangorestframework-datatables](https://pypi.org/project/djangorestframework-datatables/)がある。データテーブルのリクエストパラメータ（フィルター、ソート、ページングなど）を解析し、それに基づいてクエリを構築してデータを取得する。そして、取得したデータをデータテーブルの要件に従って整形し、JSONレスポンスとして返す。

ちなみに、ajax通信をするときに、datatableのsearchやsortingのパラメータを取得するには以下のようにすると取得できる。

```js
const params = Object.assign({}, {format: 'datatables'}, dt.ajax.params())
```

### その他

Djangoだけでなく、Laravelなどその他のフレームワークや言語でもつかうことができる。
サーバサイドとの連携例は以下の公式ドキュメントにのっている。

https://datatables.net/examples/server_side/simple.html