lightning-datatableのCustom Data Typeの使い方

# はじめに

Salesforceの新しいフロントエンドフレームワークである[Lightning Web Component](https://developer.salesforce.com/docs/component-library/documentation/lwc)のお話です。

`lightning-datatable`コンポーネントはいわゆるSalesforceの一般的なテーブルUIを実現するコンポーネントです。
しかし、**リンクが貼れない**、**ボタンが置けない**、などなかなかカスタマイズが効きません。

> 追記（2019/04/08）
> ボタンは `type:'button'` や `type:'button-icon'` で置けました。

ちゃんと[ドキュメント](https://developer.salesforce.com/docs/component-library/bundle/lightning-datatable/documentation)を読んでみると、`Create Custom Data Types`という章があることに気づいたので、試してみました。

しかし、ちょっとつまずいたので、記事にまとめて、コードも公開しておきます。

# 作るもの

ドキュメントの例のようにカラムに`deleteRowButton`というデータ型を指定すると削除ボタンを表示するようにします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/27267/1a279866-6854-c1a3-e601-72150f00fc6e.png)

# ソースコード

リポジトリ作って置いておきました。
https://github.com/atskimura/lightning-datatable-custom-datatype-example

# 作り方

３つのコンポーネントを作る必要があります。

* myDatatableDemo: 実際画面に配置するコンポーネント
* myDatatable: lightning-datatableを継承したコンポーネント
* datatableDeleteRowBtn: 削除ボタン部分のコンポーネント

## myDatatableDemo

実際に画面に配置するコンポーネントです。カスタムdatatableコンポーネントを利用する側です。

```html:myDatatableDemo.html
<template>
  <c-my-datatable
      key-field="id"
      data={data}
      columns={columns}
      ondeleterow={deleteRow}
      hide-checkbox-column>
  </c-my-datatable>
</template>
```

ビューではこの後作る`myDatatable`コンポーネントを利用しています。
ドキュメントと違って他のコンポーネントを利用するにはネームスペース（今回はローカルなので`c`）が必要です。
`ondeleterow`はこの後作成する`datatableDeleteRowBtn`で発火します。

```js:myDatatableDemo.js
import { LightningElement, track } from 'lwc';

const columns = [
    {
      label: 'Name',
      fieldName: 'name',
    },
    {
        label: 'Delete',
        type: 'deleteRowButton',
        fieldName: 'id',
        fixedWidth: 70,
        typeAttributes: {
          attrA: { fieldName: 'attrA' },
          attrB: { fieldName: 'attrB' },
        },
    },
];

export default class MyDatatableDemo extends LightningElement {
    @track data = [
      {
        id: '1',
        name: 'Name1',
        attrA: 'A1',
        attrB: 'B1',
      },
      {
        id: '2',
        name: 'Name2',
        attrA: 'A2',
        attrB: 'B2',
      }
    ];
    @track columns = columns;

    deleteRow(event) {
        const { rowId } = event.detail;
        window.console.log(rowId, event);
        // Remove the row
    }
}
```

`columns`で`lightning-datatable`コンポーネントにはない`deleteRowButton`というタイプを指定しています。

## myDatatable

lightning-datatableを継承したコンポーネントです。カスタムデータタイプを使用するには継承したコンポーネントを作る必要があります。面倒ですね。

```js:myDatatable.js
import LightningDatatable from 'lightning/datatable';
import deleteRow from './deleteRow.html';

export default class MyDatatable extends LightningDatatable {
   static customTypes = {
       deleteRowButton: {
           template: deleteRow,
           // Provide template data here if needed
           typeAttributes: ['attrA', 'attrB'],
       }
      //more custom types here
   };
}
```

`LightningDatatable`を継承したクラスを作り、`customTypes`に追加したいカスタムデータ型を定義するだけです。
利用するテンプレート（`template`）と値を渡したいプロパティ名（`typeAttributes`）を設定します。

```html:deleteRow.html
<template>
  <c-datatable-delete-row-btn
      data-navigation="enable"
      row-id={value}
      attr-a={typeAttributes.attrA}
      attr-b={typeAttributes.attrB}>
  </c-datatable-delete-row-btn>
</template>
```

テンプレートは`deleteRow.html`として`myDatatable.js`と同階層に作ります。
`datatableDeleteRowBtn`コンポーネントを呼び出しています。
`value`では`columns`の定義で`fieldName`に指定したプロパティ値が取得できます。
`typeAttributes.attrA`のようにするとそのカラムのデータの`attrA`プロパティの値が取得できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/27267/970a534c-4a52-a9cf-5c21-91f4bff8d9b7.png)

こういうファイル構造になります。
`myDatatable.html`は空でよいです。

## datatableDeleteRowBtn

`deleteRowButton`型に対応する削除ボタン部分のコンポーネントです。
これは普通にコンポーネントを作ればよいです。

```html:datatableDeleteRowBtn.html
<template>
    <div style="text-align: center;">
        <lightning-button-icon
            icon-name="utility:delete"
            onclick={fireDeleteRow}>
        </lightning-button-icon>
    </div>
</template>
```

ビューでは削除ボタンを置いているだけです。

```js:datatableDeleteRowBtn.js
import { LightningElement, api } from 'lwc';
// Accessibility module
// import { baseNavigation } from 'lightning/datatableKeyboardMixins';
// For the render() method
// import template from './datatableDeleteRowBtn.html';

// export default class DatatableDeleteRowBtn extends baseNavigation(LightningElement) {
export default class DatatableDeleteRowBtn extends LightningElement {
    @api rowId;
    @api attrA;
    @api attrB;

    /* // Required for mixins
    render() {
        return template;
    }*/

    fireDeleteRow() {
        const event = CustomEvent('deleterow', {
            composed: true,
            bubbles: true,
            cancelable: true,
            detail: {
                rowId: this.rowId,
            },
        });
        this.dispatchEvent(event);
    }
}
```

`datatableKeyboardMixins`を使うとテーブル内でキーボードナビゲーションが使えるようになるらしいんですが、これの使い方わかりませんでした。コメントアウトしている箇所のようにドキュメント通りに書くと、何も表示されなくなってしまいます。誰か使い方わかったら教えてください。

それ以外は普通にコンポーネント作るだけです。

# 終わりに

`lightning-datatable`使えないなあと思っていましたが、意外と使えるかもしれません。
マウスオーバーしたらポップオーバーを表示するデータ型なんかを作りたいなと思います。
次のリリースでそんなデータ型が標準で追加されそうですが…