jQuery DataTables の使い方 render, row, meta...

# はじめに
jQueryの便利なライブラリの一つに[DataTables](https://datatables.net/)があります。bootstrapと組み合わせられて、ソートや検索、ページング機能を自動でいい感じの見た目の表に出力してくれる優れものです。

例えば

```json
[
{id:1,japanese:"走る",english:"run",pos:"動詞"},
{id:2,japanese:"歩く",english:"walk",pos:"動詞"},
{id:3,japanese:"鉛筆",english:"pencil",pos:"名詞"},
{id:4,japanese:"夢",english:"dream",pos:"名詞"},
]
```
のような形のjsonデータがあったとして、それをどうdataTablesを使ってきれいな表にしていくかについて解説します。

# はじめのコード
```html
<html>
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css"/>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  </head>
<body>
  <!-- 追加のCSS -->
  <style>

  </style>

  <table class='table table-stripe' id="lingTable">
    <thead>
      <tr><th>#</th><th>日本語</th><th>英語</th>
        <th>品詞</th></tr>
    </thead>
  </table>

  <!-- dataTables bootstrap4を使うためのJSファイル -->
  <script
  src="https://code.jquery.com/jquery-3.3.1.min.js"
  integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
  crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/1.10.19/js/dataTables.bootstrap4.min.js"></script>
  <!-- 独自定義JS -->
  <script type="text/javascript">
    const lingData=[
      {id:1,japanese:"走る",english:"run",pos:"動詞"},
      {id:2,japanese:"歩く",english:"walk",pos:"動詞"},
      {id:3,japanese:"鉛筆",english:"pencil",pos:"名詞"},
      {id:4,japanese:"夢",english:"dream",pos:"名詞"},
    ]
    const dtSetting={
       destroy: true,
       data: lingData,
       language: {
         url: "https://cdn.datatables.net/plug-ins/3cfcc339e89/i18n/Japanese.json"
       },
       columns: [
         {data:"id"},
         { data: "japanese"},
         { data: "english"},
         { data: "pos"}
       ]
    };
    $('#lingTable').DataTable(dtSetting);
  </script>
</body>
</html>

```
とりあえずこのコードをコピペして好きな名前のhtmlファイルを作ってGoogle Chromeなどのブラウザで開いてみてください。
成功すると次のような表が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256917/51d64326-f80b-cc61-9a09-328876148b94.png)
ソートや検索機能などが実装されています。細かい調整は[DataTablesの使い方](https://qiita.com/nissuk/items/7ac59af5de427c0585c5)を参照してください。

さて、独自定義JSと書かれた中を見てください。

- `const lingData=[...]`で先程のjsonを定義しています。通常の運用では`ajax`などを使って取ってくるでしょう。
- その下の`const dtSetting={...}`というオブジェクトがDataTablesに渡す設定オブジェクトです。
- `destroy:true`は再描画を可能にするためのもので、trueにしておいたほうが便利です。(後ほど出てくるので今は何を言っているかわからなくてもあまり気にしないでください。)
- `data:lingData`でlingDataの中身を読み込むと設定しています。
- 次の`language:...`は日本語表記にする設定でこれがないとX件表示などが英語表記になってしまいます。
- 最後の`columns:[]`でどの列にどの要素を指定するかを順番に定義しています。列の数を増やすためには個々の要素の数を増やすと同時に、`<thead>`タグ内の`<th>`タグの数を増やす必要があります。そうしないとエラーします。**よくエラーするポイントです。**  

```json
columns: [
   { data: "id"},
   { data: "japanese"},
   { data: "english"},
   { data: "pos"},
   { data: "pos"} /*追加*/
]
```
のように追加するならば、

```html
    <thead>
      <tr><th>#</th><th>日本語</th><th>英語</th>
        <th>品詞</th><th>品詞2</th></tr>
    </thead>

```
としないといけないということです。(`<th>品詞2</th>`を追加しました。) 
表の出力はこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256917/1f7adf96-2a9c-193e-51a9-eb18a42d1f99.png)


# render要素
さて、動詞だけ色を付けて強調してみましょう。
`columns`の`render`要素に関数オブジェクト(`function(){...}`のかたちで作られるオブジェクト)を付加します。

>関数オブジェクトについては[このリンク](https://uhyohyo.net/javascript/1_4.html)に詳しく解説されています。オブジェクトはJavaScriptを使う上で非常に重要になる概念です。

コード全体です。

```html
<html>
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css"/>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  </head>
<body>
  <!-- 追加のCSS -->
  <style>
body{
  margin:20px;
}
  </style>

  <table class='table table-stripe' id="lingTable">
    <thead>
      <tr><th>#</th><th>日本語</th><th>英語</th>
        <th>品詞</th></tr>
    </thead>
  </table>

  <!-- dataTables bootstrap4を使うためのJSファイル -->
  <script
  src="https://code.jquery.com/jquery-3.3.1.min.js"
  integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
  crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/1.10.19/js/dataTables.bootstrap4.min.js"></script>
  <!-- 独自定義JS -->
  <script type="text/javascript">
    const lingData=[
      {id:1,japanese:"走る",english:"run",pos:"動詞"},
      {id:2,japanese:"歩く",english:"walk",pos:"動詞"},
      {id:3,japanese:"鉛筆",english:"pencil",pos:"名詞"},
      {id:4,japanese:"夢",english:"dream",pos:"名詞"},
    ]
    const dtSetting={
       destroy: true,
       data: lingData,
       language: {
         url: "https://cdn.datatables.net/plug-ins/3cfcc339e89/i18n/Japanese.json"
       },
       columns: [
         { data:"id"},
         { data: "japanese"},
         { data: "english"},
         { data: "pos", render:function(arg){
           if(arg=="動詞"){
             return `<span style='color:red;'>${arg}</span>`;
           }else{
             return arg;
           }}
         }
       ]
    };
    $('#lingTable').DataTable(dtSetting);
  </script>
</body>
</html>
```

関数オブジェクトに慣れていない人は次のように書いたほうがわかりやすいかもしれません。

```html
  <script type="text/javascript">
    const lingData=[
      {id:1,japanese:"走る",english:"run",pos:"動詞"},
      {id:2,japanese:"歩く",english:"walk",pos:"動詞"},
      {id:3,japanese:"鉛筆",english:"pencil",pos:"名詞"},
      {id:4,japanese:"夢",english:"dream",pos:"名詞"},
    ]
    const verbred=function(arg){
      if(arg=="動詞"){
        return `<span style='color:red;'>${arg}</span>`;
      }else{
        return arg;
      }
    };

    const dtSetting={
       destroy: true,
       data: lingData,
       language: {
         url: "https://cdn.datatables.net/plug-ins/3cfcc339e89/i18n/Japanese.json"
       },
       columns: [
         {data:"id"},
         { data: "japanese"},
         { data: "english"},
         { data: "pos", render:verbred }
       ]
    };
    $('#lingTable').DataTable(dtSetting);
  </script>

```
いったん変数`verbred`に関数オブジェクトを代入して使っています。

いずれの場合でも次のような結果になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256917/d4468066-66fd-0c92-5776-45e1c65d0065.png)

# row ~複数列(キー)のデータを使う~
複数の列のデータを使いたいというシチュエーションはよく出てきます。今回は品詞が動詞だったときに単語を青くすることを考えましょう。次のようにします。

```html
  <script type="text/javascript">
    const lingData=[
      {id:1,japanese:"走る",english:"run",pos:"動詞"},
      {id:2,japanese:"歩く",english:"walk",pos:"動詞"},
      {id:3,japanese:"鉛筆",english:"pencil",pos:"名詞"},
      {id:4,japanese:"夢",english:"dream",pos:"名詞"},
    ]
    const dtSetting={
       destroy: true,
       data: lingData,
       language: {
         url: "https://cdn.datatables.net/plug-ins/3cfcc339e89/i18n/Japanese.json"
       },
       columns: [
         {data:"id"},
         { data: "japanese"},
         { data: "english",
           render:function(data,type,row){
             if(row.pos=="動詞"){
               return `<span style='color:blue;'>${data}</span>`;
             }else{
               return data; //row.englishでも良い。
             }
           }
         },
         { data: "pos", render:function(arg){
           if(arg=="動詞"){
             return `<span style='color:red;'>${arg}</span>`;
           }else{
             return arg;
           }}
         }
       ]
    };
    $('#lingTable').DataTable(dtSetting);
  </script>
```

`render`に3引数を持つ関数オブジェクトを登録することで、3つめの引数`row`から自分以外のキーのデータにアクセスできます。関数オブジェクト内で`console.log(row);`などしてやるとよくわかるかもしれません。

# meta ~jsonの中で何行目のデータか探る~
ボタンをつけて、ボタンを押したらその行のデータを整形して表示するようにしましょう。ボタン自身が属する列のデータが、元データ`lingData`の中の何個目のデータなのかがボタンに付加しておきたい情報です。次のようになります。

```html
<html>
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css"/>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  </head>
<body>
  <!-- 追加のCSS -->
  <style>
body{
  margin:20px;
}
  </style>

  <table class='table table-stripe' id="lingTable">
    <thead>
      <tr><th>#</th><th>日本語</th><th>英語</th>
        <th>品詞</th><th>出力</th></tr>
    </thead>
  </table>

  <!-- dataTables bootstrap4を使うためのJSファイル -->
  <script
  src="https://code.jquery.com/jquery-3.3.1.min.js"
  integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
  crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/1.10.19/js/dataTables.bootstrap4.min.js"></script>
  <!-- 独自定義JS -->
  <script type="text/javascript">
    const lingData=[
      {id:1,japanese:"走る",english:"run",pos:"動詞"},
      {id:2,japanese:"歩く",english:"walk",pos:"動詞"},
      {id:3,japanese:"鉛筆",english:"pencil",pos:"名詞"},
      {id:4,japanese:"夢",english:"dream",pos:"名詞"},
    ]
    const dtSetting={
       destroy: true,
       data: lingData,
       language: {
         url: "https://cdn.datatables.net/plug-ins/3cfcc339e89/i18n/Japanese.json"
       },
       columns: [
         { data:"id"},
         { data: "japanese"},
         { data: "english",
           render:function(data,type,row){
             if(row.pos=="動詞"){
               return `<span style='color:blue;'>${data}</span>`;
             }else{
               return data; //row.englishでも良い。
             }
           }
         },
         { data: "pos", render:function(arg){
           if(arg=="動詞"){
             return `<span style='color:red;'>${arg}</span>`;
           }else{
             return arg;
           }}
         },
         {data:"id",
           render:function(data,type,row,meta){
             return `<button class="btn btn-danger output" data-jnum="${meta.row}">出力</button>`;
           }
         },
       ]
    };
    $('#lingTable').DataTable(dtSetting);
    $(document).on('click','.output',function(){
      const jnum=$(this).data('jnum');
      alert(`日本語表記:${lingData[jnum]["japanese"]},英語表記:${lingData[jnum]["english"]},品詞:${lingData[jnum]["pos"]}`);
    })
  </script>
</body>
</html>

```
関数オブジェクトに第4引数`meta`を追加すると`meta.row`で今回欲しい情報が取ってこれます。
アラートを出すところは`$(document).on(...`で定義しています。`output`クラスはDataTable関数によって後から作られるので、`$('.output').on(...`では動きません。
jQueryの便利機能、`data-xxx`の形のattributeの値は、`$(...).data('xxx')`で取得できることを利用しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256917/db574280-b857-28c0-6a5a-84f470d7ceba.png)
出力ボタンを押すと次のようなアラートが出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256917/17d3ea8c-dd95-880c-da33-4f66b4958607.png)


これを応用すると編集機能などが作れます。

### ※2020/5/5 追記
同様の機能はフレームワーク[vue](https://jp.vuejs.org/index.html)とそのUIフレームワーク[vuetify](https://vuetifyjs.com/ja/)を用いても実現できます。vuetifyの[datatable](https://vuetifyjs.com/ja/components/data-tables/)を使って作るのが最近のマイブームです。