kintnoeのレコード詳細画面にレコード内のサブテーブルを更新するボタンを作る

最近、仕事でkintoneに触れることが多い。 今日はkintoneのレコード詳細画面に、レコード内のサブテーブルを更新するボタンを作ってみたのでまとめてみる。

以下のようにすればできそうだけどこれだとダメ。

const updateRecord = () => {
  const { record } = kintone.app.record.get();
  record.SUB_TABLE.value.forEach(row => {
    row.value.example.value = "example";
  });
  kintone.app.record.set({ record });
};

kintone.events.on(["app.record.detail.show"], () => {
  if (document.getElementById("updateButton") === null) {
    const myIndexButton = document.createElement("button");
    myIndexButton.id = "updateButton";
    myIndexButton.innerText = "更新ボタン";
    myIndexButton.onclick = updateRecord;
    kintone.app.record.getHeaderMenuSpaceElement().appendChild(myIndexButton);
  }
});

ドキュメントにも以下のように書いてあったりする。 developer.cybozu.io

kintone.events.on のインベントハンドラ内で kintone.app.record.set および kintone.mobile.app.record.set を実行することはできません。 上記のイベントハンドラ内ではレコードデータの取得は引数のeventオブジェクトを、レコードデータの更新はeventオブジェクトのreturnを使用してください。

とはいえ、myIndexButton.onclickに登録した関数にeventオブジェクトを渡してeventオブジェクトをreturnしても意味はない。

const updateRecord = (event) => () => {
  const { record } = event;
  record.SUB_TABLE.value.forEach(row => {
    row.value.example.value = "example";
  });
  return event;
};

ということで、kintone JS SDKを使う。

developer.cybozu.io

これを使うとこんな感じでかける。

const kintoneConnection = new kintoneJSSDK.Connection();
const kintoneRecord = new kintoneJSSDK.Record({ connection: kintoneConnection });

const updateRecord = async () => {
  const { record } = kintone.app.record.get();
  const changedTable = record.SUB_TABLE.value.map((row) => {
    row.value.example.value = "example";
    return row;
  });

  try {
    await kintoneRecord.updateRecordByID({
      app: kintone.app.getId(),
      id: kintone.app.record.getId(),
      record: {
        SUB_TABLE: {
          value: changedTable,
        },
      },
    });
    window.location.reload();
  } catch (error) {
    console.log(error)
  }
};

kintone.events.on(["app.record.detail.show"], () => {
  if (document.getElementById("updateButton") === null) {
    const myIndexButton = document.createElement("button");
    myIndexButton.id = "updateButton";
    myIndexButton.innerText = "更新ボタン";
    myIndexButton.onclick = updateRecord;
    kintone.app.record.getHeaderMenuSpaceElement().appendChild(myIndexButton);
  }
});

サブテーブルの各レコードに設定する値を非同期な関数(以下だとasynchronousFunction())で取得している場合はこんな感じでいけます。

const updateRecord = async () => {
  const { record } = kintone.app.record.get();
  const changedTable = await Promise.all(
    record.SUB_TABLE.value.map(async (row) => {
      row.value.example.value = await asynchronousFunction();
      return row;
    }),
  );

  try {
    await kintoneRecord.updateRecordByID({
      app: kintone.app.getId(),
      id: kintone.app.record.getId(),
      record: {
        SUB_TABLE: {
          value: changedTable,
        },
      },
    });
    window.location.reload();
  } catch (error) {
    console.log(error)
  }
};