Table and ReadOnlyTable customization
概要
今回は Table と ReadOnlyTable コンポーネントの使い方の違い、活用とカスタマイズ方法について説明します。
以下のシナリオを想定しています。
- 基本的な使い方 (Table, ReadOnlyTable)
- 一つのセルに複数のコンポーネント表示 (Table)
- 依存列 (Table)
- 入れ子テーブル (Table)
使用するコンポーネント
Table と ReadOnlyTable の使い方の違い
基本的に Table と ReadOnlyTable コンポーネントは同じような構造になっています。
ReadOnlyTable コンポーネントは、読み取り専用のテーブルを表示することができます。つまり、ユーザーが操作できないプレーンなテキストのみ表示することができます。
一方で、Table コンポーネントは、データを変更したり行の追加/削除をしたりとテーブルのセルに表示されるコンポーネントを操作することができます。
最大の違いは、Table の columns
プロパティが render
プロパティ(columns.render
)を持っていることです。このプロパティは、ユーザーが操作できるセルに表示する要素を設定することができます。さらに、actionButton
プロパティ(table.actionButton
)を使って行の追加/削除ボタンの表示/非表示を切り替えることができます。
change イベント の理解
Table の change
イベントの流れを理解すると、カスタマイズがしやすくなります。
テーブルのセルは、セルの中のコンポーネントの change
イベントをリッスンして、新しい値をそれに対応する field
の値に登録します。
アプリの作成
以下のフィールドを含むアプリを作成します。
- スペースフィールド(要素ID:space)
JavaScript/CSS カスタマイズ
kintone UI Component の UMD ファイルをアプリに読み込んだ上で、以下のような実装をした JavaScript ファイルをアップロードします。
ファイルのアップロード方法などは、 Quick Start をご覧ください。
基本的な Table の準備
Text コンポーネントで username を表示するような次の設定があるとします。
const renderName = (cellData) => {
const text = new Kuc.Text({ value: cellData });
return text;
};
const columns = [{ title: 'Username', field: 'username', render: renderName }];
const data = [{ username: 'user1' }, { username: 'user2' }];
const table = new Kuc.Table({columns, data});
const space = kintone.app.record.getSpaceElement('space');
space.appendChild(table);
UI 上に表示
最初のセルの入力値を編集した場合、Text コンポーネントは detail.value = 'user1 edited'
を含む change
イベントをトリガーします。
そしてテーブルは値を受け取り、username
field に登録し直します。
テーブルのデータは以下のようになります。
[{ username: 'user1 edited' }, { username: 'user2' }];
event detail のカスタマイズ
テーブルが受け取る値をカスタマイズしたい場合、テーブルがその値を受け取る前に change
イベント内で編集する必要があります。
上記のサンプルコードを使って、renderName
関数に以下の内容を追加します。
...
const renderName = (cellData) => {
const text = new Text({ value: cellData });
// Modify the value before it bubble to table cell
text.addEventListener('change', (event) => {
event.detail.value = 'modified value' // add any value you want set to username;
});
return text;
};
...
最初のセルの入力値を編集した場合、テーブルが受け取る値は必ず 'modified value'
になります。
カスタマイズ例
基本的な使い方
ReadOnlyTable
読み取り専用のテーブルを表示します。
Show code
const columns = [
{
title: 'Name',
field: 'name',
},
{
title: 'Gender',
field: 'gender',
},
{
title: 'Address',
field: 'address',
},
];
const data = [
{
name: 'John Brown',
gender: 'male',
address: 'osaka-japan',
},
{
name: 'Jim Green',
gender: 'female',
address: 'tokyo-japan',
},
{
name: 'Joe Black',
gender: 'male',
address: 'hochiminh-vietnam',
},
];
const readOnlyTable = new Kuc.ReadOnlyTable({columns, data});
const space = kintone.app.record.getSpaceElement('space');
space.appendChild(readOnlyTable);
Table
表示されているコンポーネントを操作できるテーブルを表示します。
columns.render
関数を使って、セルに表示されるコンポーネントを設定します。以下のサンプルコードの renderGender
と renderAddress
関数を確認してください。
Show code
// render gender column with dropdown
const renderGender = (cellData) => {
const radioButton = new Kuc.RadioButton({
items: [
{
label: 'Male',
value: 'male',
},
{
label: 'Female',
value: 'female',
},
],
itemLayout: 'vertical',
value: cellData,
});
return radioButton;
};
// render address column with dropdown
const renderAddress = (cellData) => {
const country = cellData.split('-')[1];
const dropdownCountry = new Kuc.Dropdown({
items: [
{
label: 'Viet Nam',
value: 'vietnam',
},
{
label: 'Japan',
value: 'japan',
},
],
value: country,
});
return dropdownCountry;
};
const columns = [
{
title: 'Name',
field: 'name',
},
{
title: 'Gender',
field: 'gender',
render: renderGender,
},
{
title: 'Address',
field: 'address',
render: renderAddress,
},
];
const data = [
{
name: 'John Brown',
gender: 'male',
address: 'osaka-japan',
},
{
name: 'Jim Green',
gender: 'female',
address: 'tokyo-japan',
},
{
name: 'Joe Black',
gender: 'male',
address: 'hochiminh-vietnam',
},
];
const table = new Kuc.Table({columns, data});
const space = kintone.app.record.getSpaceElement('space');
space.appendChild(table);
一つのセルに複数のコンポーネント表示(Table)
columns.render
関数を使って、一つのセルに複数のコンポーネントを表示します。
以下のサンプルコードでは、同じセル内に 2つの Dropdown(city と country)を表示します。
Show code
const renderAddress = (cellData, rowData) => {
// the format of cellData: 'city-country'
const city = cellData.split('-')[0];
const country = cellData.split('-')[1];
const dropdownCity = new Kuc.Dropdown({
items: [
{
label: 'Tokyo',
value: 'tokyo',
},
{
label: 'Osaka',
value: 'osaka',
},
{
label: 'Ho Chi Minh',
value: 'hochiminh',
},
],
value: city,
});
dropdownCity.addEventListener('change', (event) => {
const _country = rowData.address.split('-')[1];
event.detail.value = `${event.detail.value}-${_country}`;
});
const dropdownCountry = new Kuc.Dropdown({
items: [
{
label: 'Viet Nam',
value: 'vietnam',
},
{
label: 'Japan',
value: 'japan',
},
],
value: country,
});
dropdownCountry.addEventListener('change', (event) => {
const _city = rowData.address.split('-')[0];
event.detail.value = `${_city}-${event.detail.value}`;
});
const container = document.createElement('div');
container.style.display = 'flex';
container.appendChild(dropdownCountry);
container.appendChild(dropdownCity);
return container;
};
const data = [
{
name: 'John Brown',
gender: 'male',
address: 'osaka-japan',
},
{
name: 'Jim Green',
gender: 'female',
address: 'tokyo-japan',
},
{
name: 'Joe Black',
gender: 'male',
address: 'hochiminh-vietnam',
},
];
const columns = [
{
title: 'Name',
field: 'name',
},
{
title: 'Address',
field: 'address',
render: renderAddress,
},
];
const table = new Kuc.Table({columns, data});
const space = kintone.app.record.getSpaceElement('space');
space.appendChild(table);
依存列(Table)
依存列を作ります。
country Dropdown の値が変更されたら city Dropdown の値が変更されます。
Show code
// Each country will have corresponding cities
const relatedData = {
japan: [
{label: 'Tokyo', value: 'tokyo'},
{label: 'Osaka', value: 'osaka'},
],
vietnam: [
{label: 'Ha Noi', value: 'hanoi'},
{label: 'Ho Chi Minh', value: 'hochiminh'},
],
};
const renderCity = (cellData, rowData) => {
const dropdownCity = new Kuc.Dropdown({
items: [
{
label: 'Tokyo',
value: 'tokyo',
},
{
label: 'Ho Chi Minh',
value: 'hochiminh',
},
],
value: cellData,
});
// Logic update city when country column changed
lastRenderedCountryComponent.addEventListener('change', (event) => {
dropdownCity.items = relatedData[event.detail.value];
rowData.city = '';
});
return dropdownCity;
};
let lastRenderedCountryComponent;
const renderCountry = (cellData) => {
const dropdownCountry = new Kuc.Dropdown({
items: [
{
label: 'Viet Nam',
value: 'vietnam',
},
{
label: 'Japan',
value: 'japan',
},
],
value: cellData,
});
lastRenderedCountryComponent = dropdownCountry;
return dropdownCountry;
};
const columns = [
{
title: 'Country',
field: 'country',
render: renderCountry,
},
{
title: 'City',
field: 'city',
render: renderCity,
},
];
const data = [
{
country: 'japan',
city: 'tokyo',
},
{
country: 'vietnam',
city: 'hochiminh',
},
];
const table = new Kuc.Table({columns, data});
const space = kintone.app.record.getSpaceElement('space');
space.appendChild(table);
入れ子テーブル(Table)
入れ子テーブルを作って各行にさらに詳細な情報を表示します。
Show code
const renderCity = (cellData) => {
const dropdown = new Kuc.Dropdown({
items: [
{label: 'Tokyo', value: 'tokyo'},
{label: 'Ho Chi Minh', value: 'hochiminh'},
],
value: cellData,
});
return dropdown;
};
const renderCountry = (cellData) => {
const renderSubTable = (cellDataSubTable) => {
const dropdown = new Kuc.Dropdown({
items: [
{label: 'Japan', value: 'japan'},
{label: 'Viet Nam', value: 'vietnam'},
],
value: cellDataSubTable,
});
return dropdown;
};
const columnsSubTable = [
{
title: 'Sub Table',
field: 'dropdown',
render: renderSubTable,
},
];
const dataSubTable = [];
for (let i = 0; i < cellData.split(',').length; i++) {
dataSubTable.push({dropdown: cellData.split(',')[i]});
}
const subTable = new Kuc.Table({
columns: columnsSubTable,
data: dataSubTable,
});
subTable.addEventListener('change', (subTableEvent) => {
const _dataSubTable = subTableEvent.detail.data;
let countries = '';
for (let i = 0; i < _dataSubTable.length; i++) {
countries += _dataSubTable[i].dropdown;
if (i !== _dataSubTable.length - 1) {
countries += ',';
}
}
subTableEvent.detail.value = countries;
});
return subTable;
};
const columns = [
{
title: 'Country',
field: 'country',
render: renderCountry,
},
{
title: 'City',
field: 'city',
render: renderCity,
},
];
const data = [
{
city: 'tokyo',
country: 'japan',
},
{
city: 'hochiminh',
country: 'vietnam',
},
];
const table = new Kuc.Table({columns, data});
const space = kintone.app.record.getSpaceElement('space');
space.appendChild(table);
本記事は、 2023 年 2 月時点の kintone と Google Chrome で確認したものになります。
また、カスタマイズに使用した kintone UI Component のバージョンは、v1.9.0 です。