MENU

【DataTables】物理値から表示用の論理値を表示する方法

APIやDBでは129のようなコード値を持ち、画面では「有効」「停止」「削除済み」のようなラベルで見せたいことがあります。

DataTablesではcolumns.renderを使うと、データとして持つ値と画面に出す値を分けられます。

目次

公式ページ

やりたいこと

たとえば、以下のようなデータがあるとします。

const users = [
    { id: 1, name: '山田 太郎', status: '1' },
    { id: 2, name: '佐藤 花子', status: '2' },
    { id: 3, name: '鈴木 一郎', status: '9' }
];

statusには物理値として129が入っています。

このままDataTablesに表示すると、画面にも129が表示されます。

new DataTable('#usersTable', {
    data: users,
    columns: [
        { data: 'id', title: 'ID' },
        { data: 'name', title: '名前' },
        { data: 'status', title: 'ステータス' }
    ]
});

ユーザーに見せたいのは物理値ではなく、次のような表示用の値です。

| 物理値 | 表示用の論理値 |
| — | — |
| 1 | 有効 |
| 2 | 停止 |
| 9 | 削除済み |

columns.renderで表示値を変換する

DataTablesでは、列定義のrenderで表示内容を加工できます。

const STATUS_LABELS = {
    '1': '有効',
    '2': '停止',
    '9': '削除済み'
};

new DataTable('#usersTable', {
    data: users,
    columns: [
        { data: 'id', title: 'ID' },
        { data: 'name', title: '名前' },
        {
            data: 'status',
            title: 'ステータス',
            render: function (data) {
                return STATUS_LABELS[data] ?? '不明';
            }
        }
    ]
});

これで、元データのstatus129のまま、画面には「有効」「停止」「削除済み」と表示できます。

typeを見て表示、検索、ソートを分ける

render関数には、DataTablesからdatatyperowなどが渡されます。

render: function (data, type, row) {
    // data: columns.dataで指定した値
    // type: display / filter / sort / type など
    // row: 行全体のデータ
}

重要なのはtypeです。

DataTablesは、表示、検索、ソートなどの用途ごとにrenderを呼び出します。

たとえば、表示と検索では「有効」を使い、ソートでは元の物理値を使いたい場合は、次のように書けます。

const STATUS_LABELS = {
    '1': '有効',
    '2': '停止',
    '9': '削除済み'
};

new DataTable('#usersTable', {
    data: users,
    columns: [
        { data: 'id', title: 'ID' },
        { data: 'name', title: '名前' },
        {
            data: 'status',
            title: 'ステータス',
            render: function (data, type) {
                if (type === 'display' || type === 'filter') {
                    return STATUS_LABELS[data] ?? '不明';
                }

                return data;
            }
        }
    ]
});

この書き方にすると、画面表示と検索にはラベルを使い、ソートや型判定には元の物理値を使えます。

表示順を制御したい場合

物理値の大小と、画面上の並び順が一致しない場合もあります。

たとえば、以下の順番で並べたいとします。

  1. 有効
  2. 停止
  3. 削除済み

その場合は、表示用ラベルとは別にソート用の値を用意します。

const STATUS_LABELS = {
    '1': '有効',
    '2': '停止',
    '9': '削除済み'
};

const STATUS_SORT_ORDER = {
    '1': 1,
    '2': 2,
    '9': 3
};

new DataTable('#usersTable', {
    data: users,
    columns: [
        { data: 'id', title: 'ID' },
        { data: 'name', title: '名前' },
        {
            data: 'status',
            title: 'ステータス',
            render: function (data, type) {
                if (type === 'display' || type === 'filter') {
                    return STATUS_LABELS[data] ?? '不明';
                }

                if (type === 'sort' || type === 'type') {
                    return STATUS_SORT_ORDER[data] ?? 999;
                }

                return data;
            }
        }
    ]
});

これで、表示は「有効」「停止」「削除済み」のまま、ソートはSTATUS_SORT_ORDERの値で制御できます。

rowを使って複数項目から表示値を作る

renderでは、行全体のデータをrowから参照できます。

たとえば、statusisLockedを組み合わせて表示を変えたい場合です。

const users = [
    { id: 1, name: '山田 太郎', status: '1', isLocked: false },
    { id: 2, name: '佐藤 花子', status: '1', isLocked: true },
    { id: 3, name: '鈴木 一郎', status: '2', isLocked: false }
];

const STATUS_LABELS = {
    '1': '有効',
    '2': '停止',
    '9': '削除済み'
};

new DataTable('#usersTable', {
    data: users,
    columns: [
        { data: 'id', title: 'ID' },
        { data: 'name', title: '名前' },
        {
            data: 'status',
            title: 'ステータス',
            render: function (data, type, row) {
                if (type !== 'display' && type !== 'filter') {
                    return data;
                }

                const label = STATUS_LABELS[data] ?? '不明';
                return row.isLocked ? `${label}(ロック中)` : label;
            }
        }
    ]
});

dataだけで足りない場合は、rowを使って行全体から表示値を組み立てると便利です。

共通関数にして使い回す

ステータス変換を複数のDataTablesで使う場合は、変換処理を共通関数にしておくと楽です。

const STATUS_LABELS = {
    '1': '有効',
    '2': '停止',
    '9': '削除済み'
};

const STATUS_SORT_ORDER = {
    '1': 1,
    '2': 2,
    '9': 3
};

function renderStatus(data, type) {
    if (type === 'display' || type === 'filter') {
        return STATUS_LABELS[data] ?? '不明';
    }

    if (type === 'sort' || type === 'type') {
        return STATUS_SORT_ORDER[data] ?? 999;
    }

    return data;
}

new DataTable('#usersTable', {
    data: users,
    columns: [
        { data: 'id', title: 'ID' },
        { data: 'name', title: '名前' },
        {
            data: 'status',
            title: 'ステータス',
            render: renderStatus
        }
    ]
});

この形にしておくと、別の一覧でもrender: renderStatusと書くだけで同じ変換を使えます。

HTMLを返す場合の注意

renderではHTML文字列を返すこともできます。

function renderStatus(data, type) {
    const label = STATUS_LABELS[data] ?? '不明';

    if (type === 'display') {
        return `<span class="status-label status-${data}">${label}</span>`;
    }

    if (type === 'filter') {
        return label;
    }

    return data;
}

ただし、外部入力をそのままHTMLとして返すとXSSの原因になります。

表示用HTMLを返す場合は、コード値のように安全な値だけを使う、または文字列をエスケープしてから表示するようにしてください。

まとめ

物理値を表示用ラベルに変換するなら、columns.renderに変換処理をまとめます。

基本は、物理値と表示ラベルの対応表を作り、renderで変換するだけです。

検索やソートも考慮する場合は、typeを見て返す値を分けます。

  • display: 画面に表示する値
  • filter: 検索に使う値
  • sort: ソートに使う値
  • type: 型判定に使う値

物理値はデータとして保持し、画面にはユーザーに分かりやすい論理値を表示する、という分け方にすると、DataTablesの一覧を扱いやすくできます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次