🐶

【LWC】Datatableにボタンを配置する

2023/12/25に公開

はじめに

LWC(Lightning Web Component)でDatatableにボタンを配置しました。非活性化したり、色を変えたりできます。

完成形

実装方法

コード

HTML

datatable.html
<template>
    <lightning-card title="取引先一覧">
        <div class="slds-card__body slds-card__body_inner">
            <lightning-datatable
                    key-field="Id"
                    data={accounts}
                    columns={columns}
                    onrowaction={handleRowAction}
                    hide-checkbox-column>
            </lightning-datatable>
            <lightning-input  
                    value={inputText}
                    variant="label-hidden"
                    readonly>
            </lightning-input>
        </div>
    </lightning-card>
</template>

JavaScript

datatable.js
import { LightningElement } from 'lwc';

const columns = [
    { label: '取引先名', fieldName: 'Name' },
    { label: 'Webサイト', fieldName: 'Website', type: 'url' },
    { 
        type: 'button',
        typeAttributes: {
            label: { fieldName: 'buttonLabel' },
            name: 'showText',
            disabled: { fieldName: 'isOpened' }
        },
        cellAttributes: { alignment: 'center' },
        fixedWidth: 100
    },
    { 
        type: 'button-icon',
        typeAttributes: {
            iconName: 'utility:heart',
            variant: 'container',
            name: 'toggleFavorite',
        },
        cellAttributes: { 
            alignment: 'center',
            class: { fieldName: 'buttonFormat' } 
        },
        fixedWidth: 50
    }
];

export default class Datatable extends LightningElement {
    accounts = [];
    columns = columns;
    inputText;

    connectedCallback() {
        this.accounts = this.prepareTableData().map(row => ({
            ...row,
            buttonLabel: '表示',
            isOpened: false,
            isFavorite: false,
            buttonFormat: 'slds-icon-text-light'
        }));
    }

    prepareTableData() {
        return [
            {
                Id: 'xxxxxxxxxxxxxxx',
                Name: 'xxx株式会社',
                Website: 'https://xxx-example.com'
            },
            {
                Id: 'yyyyyyyyyyyyyyy',
                Name: 'yyy株式会社',
                Website: 'https://yyy-example.com' 
            },
            {
                Id: 'zzzzzzzzzzzzzzz',
                Name: 'zzz株式会社',
                Website: 'https://zzz-example.com' 
            }
        ];
    }

    handleRowAction(event) {
        const actionName = event.detail.action.name;
        const row = event.detail.row;

        switch (actionName) {
            case 'showText':
                this.showText(row);
                break;
            case 'toggleFavorite':
                this.toggleFavorite(row);
                break;
            default:
                break;
        }
    }

    showText(selectedAccount) {
        // 選択されたかどうかを判定する
        const isSelected = (Id) => {
            return Id === selectedAccount.Id;
        };

        // ボタンのラベルと活性状態を変更
        this.accounts = this.accounts.map(account => ({
            ...account,
            buttonLabel: isSelected(account.Id) ? '表示中' : '表示',
            isOpened: isSelected(account.Id)
        }));

        this.inputText = `表示中:${selectedAccount.Name}`;
    }

    toggleFavorite(selectedAccount) {
        // 反転
        selectedAccount.isFavorite = !selectedAccount.isFavorite;

        // ボタンの色を変更
        if (selectedAccount.isFavorite) {
            selectedAccount.buttonFormat = 'slds-icon-text-error';
        } else {
            selectedAccount.buttonFormat = 'slds-icon-text-light';
        }
        
        this.accounts = this.accounts.map(account => {
            if (account.Id === selectedAccount.Id) {
                return selectedAccount;
            }
            return account;
        });

        this.removeFocus();
    }

    // 強制的にフォーカスを外す
    removeFocus() {
        this.template.querySelector('lightning-input').focus();
        this.template.querySelector('lightning-input').blur();
    }
}

解説

Datatableにボタンを配置する

Datatableのカラム設定時、typeプロパティにbutton(アイコンのみのボタンの場合はbutton-icon)を指定すると、そのカラムがボタンだと認識されます。
ボタンに表示したいテキストは、typeAttributesプロパティのlabelに指定します。

ボタンにアクションを追加する

配置したボタンをクリックしたときにアクションを実行(レコードページを開く、レコードを削除する、表示を変えるなど)したい場合、HTMLのonrowactionにイベントハンドラを指定する必要があります。

handleRowAction(event) {
    const actionName = event.detail.action.name;
    const row = event.detail.row;

    switch (actionName) {
        case 'showText':
            this.showText(row);
            break;
        case 'toggleFavorite':
            this.toggleFavorite(row);
            break;
        default:
            break;
    }
}

上記のように、引数のevent.detail.action.nametypeAttributesプロパティのnameが対応しており、event.detail.rowにクリックしたボタンが存在する行のデータが保持されます。
このコードでは、アクションごとに別のメソッドを呼び出し、各アクションを実行しています。

アクション実行時にボタンの見た目を変える

もしDatatableに表示しているデータを変更したい場合、

this.accounts[index].Name = 'new株式会社';

のように、変更したいプロパティ(この場合はName)に新しい値を代入すると思います。
これでなぜ表示が変わるかというと、Datatableのカラム設定時にfieldNameとしてNameを指定しているからです。
これと同じことがボタンでも可能です。

const columns = [
    ...
    { 
        type: 'button',
        typeAttributes: {
            label: { fieldName: 'buttonLabel' },
            name: 'showText',
            disabled: { fieldName: 'isOpened' }
        },
        ...
    },
    { 
        type: 'button-icon',
        ...
        cellAttributes: { 
            ...
            class: { fieldName: 'buttonFormat' } 
        },
        ...
    }
];

上記のように、変更可能な値をカラムに設定するときにfieldNameプロパティを使用します。
あとはDatatableのデータに同一名のプロパティを設定し、アクションに応じて値を代入すればそれぞれボタンの見た目が変わります。

今回取り上げたのは、以下の3つです。

  • ボタンのラベル
  • ボタンの活性・非活性
  • ボタンのCSSクラス

これらを使いこなせれば、UI的に使い勝手のいいLWCが実装できると思います。

参考

https://techdicer.com/add-buttons-in-lwc-datatable-salesforce/
https://techdicer.com/lwc-datatable-css-styling/

終わりに

これは個人的に実務でもよく使います。ドキュメントがもう少し揃っているとうれしいですね。

Discussion