メインコンテンツまでスキップ

明細(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() による行の反映と一緒に適用されるため、解除されません。解除されるのは、あとから別の行操作が行われた場合です。

関連ページ