明細(SubTable)の操作
明細フィールド(SubTable)を JavaScript から読み書きできます。
データ構造
明細の値は 明細フィールド → 行 → 列 の3階層です。
const record = atPocket.app.record.get();
const subtable = record['field-6'];
// subtable の構造
{
type: 'SubTable',
value: [ // 行の配列
{
id: '1', // 行ID
value: { // 列UID をキーにした値
'field-6_1': { type: 'TextField', value: '商品A' },
'field-6_2': { type: 'NumberField', value: 1000 },
},
},
{
id: '2',
value: {
'field-6_1': { type: 'TextField', value: '商品B' },
'field-6_2': { type: 'NumberField', value: 2000 },
},
},
],
editable: true,
}
読み取り
atPocket.events.on('app.record.edit.show', (event) => {
const subtable = event.record['field-6'];
if (!subtable || !Array.isArray(subtable.value)) return event;
subtable.value.forEach((row) => {
console.log(`行ID: ${row.id} / 商品名: ${row.value['field-6_1'].value}`);
});
return event;
});
値の更新
const record = atPocket.app.record.get();
const subtable = record['field-6'];
subtable.value[0].value['field-6_1'].value = '商品A(改)';
subtable.value[0].value['field-6_2'].value = 1500;
atPocket.app.record.set(record);
行の追加
id を省略すると新規行として追加されます。type の指定も省略できます(フィールド定義から補完されます)。
const record = atPocket.app.record.get();
record['field-6'].value.push({
value: {
'field-6_1': { value: '商品C' },
'field-6_2': { value: 3000 },
},
});
atPocket.app.record.set(record);
連携列(RelationSelect)は、表示名だけ、またはキーだけを指定して行を追加できます。
const record = atPocket.app.record.get();
record['field-6'].value.push({
value: {
'field-6_3': { labelValue: '顧客-00004' }, // 表示名だけで追加(内部でキーを解決)
// 'field-6_3': { value: { value: '4' } }, // キー指定でも可
},
});
await atPocket.app.record.set(record);
行の削除
const record = atPocket.app.record.get();
record['field-6'].value.splice(1, 1); // 2行目を削除
atPocket.app.record.set(record);
行の並び替え
取得した行オブジェクトをそのまま入れ替えてください。行オブジェクトを作り直したり id を省いたりすると、全行が「新規追加+元の行の削除」として扱われます。
const record = atPocket.app.record.get();
record['field-6'].value.sort((a, b) =>
Number(b.value['field-6_2'].value) - Number(a.value['field-6_2'].value));
atPocket.app.record.set(record);
set() は行の全体置換です指定しなかった既存行は削除されます。残したい行はすべて配列に含めてください。
変更の検知
明細の操作は app.record.{action}.change イベントで通知されます。セルの値変更と行の操作は changes.mutation の有無で判別します。
// セル/フィールドの値変更
changes: { name: '列UID', value: 変更後の値, row: { index, id }, origin: 'user' }
// 行の操作
changes: {
name: '明細フィールドUID',
row: { index, id },
mutation: { type: 'add' | 'copy' | 'remove' | 'sort', fromIndex: 0 }, // fromIndex は sort のみ
origin: 'user',
}
- 行操作では
changes.valueは設定されません。行の配列はevent.record[event.changes.name].valueから取得してください - イベント名の末尾にUIDを付けると、購読する対象を絞れます
| イベント名 | 受け取るもの |
|---|---|
app.record.edit.change.{列UID} | その列のセル値変更のみ |
app.record.edit.change.{明細UID} | その明細の行操作、および set() 起因のその明細の値変更 |
app.record.edit.change | 上記のうち個別に購読されていないもの |
atPocket.events.on('app.record.edit.change.field-6', (event) => {
if (event.changes.mutation) {
console.log('行操作:', event.changes.mutation.type, event.changes.row.index);
}
return event;
});
セル・列単位の表示制御
setFieldDisabled / setFieldShown / setFieldStyle は、第1引数に列のUIDを指定します。行インデックスを指定するとセル1つ、省略するとその列の全行が対象になります。
// セル1つ(1行目)を編集不可にする
await atPocket.app.record.setFieldDisabled('field-6_1', true, 0);
// 列の全行を編集不可にする
await atPocket.app.record.setFieldDisabled('field-6_2', true);
// セルにスタイルを適用する
await atPocket.app.record.setFieldStyle('field-6_1', {
content: { backgroundColor: '#fff3cd' },
}, 0);
行データの中で直接指定することもできます。この場合は行の反映と同時に適用されるため、待ち合わせが不要です。
const record = atPocket.app.record.get();
record['field-6'].value.push({
value: {
'field-6_1': { value: '追加行', disabled: true, style: { color: 'red' } },
},
});
atPocket.app.record.set(record);
行の追加・コピー・削除・並び替えでは、明細のDOMが作り直されます。そのため、その行操作より前に適用されていた次のものが失われます。
setFieldDisabled/setFieldShown/setFieldStyleで適用した状態- 過去の
record.set()で指定したdisabled/visible/style addEventListenerで付けたリスナー、appendChildで挿入した独自のDOM要素getFieldElementで取得して保持した要素の参照
行操作の change イベント(changes.mutation を伴うもの)で再適用してください。
set() で指定した状態は残ります上の例のように、行データの中で disabled / visible / style を指定した場合、その指定はその set() による行の反映と一緒に適用されるため、解除されません。解除されるのは、あとから別の行操作が行われた場合です。