【AppSheet×GAS】フォームで指定行数を一括追加する方法

【AppSheet×GAS】フォームで指定行数を一括追加する方法

AppSheetでは表形式の追加ができない

AppSheetで開発していると必ずぶつかる問題として、

「Excelのように表形式でサクサク行を追加できない」

というのがあります。

例えば、見積書を作成するシーン。
「これから明細を10行入力したい」と思っても、標準機能では「Add」ボタンを押して入力して保存、また「Add」を押して...という繰り返しになります。

Excelでの業務に慣れている利用者にとってはかなり使いづらく感じる点といえるでしょう。

表形式での「編集」はできる

結論からいうと、見た目が表形式になっている状態での追加はできません。

ただし、ベータ版ではありますが、表形式の編集は可能です。

Viewを「table」にして、「Enable QuickEdit (beta)」をオンにすると表形式での編集ができます。

しかし、これはあくまでも追加された行の編集です。

最初から行が用意されてあり、そこに値を追加していくということはできません。

考え方と実装の全体像

では、どうすれば良いでしょうか?

Enable QuickEditを使って表形式での編集はできるため、「行の追加」さえできれば何とかなりそうです。

そのため、操作のフローとしては以下のようになります:

①AppSheetのフォームを使って数字を入力
②入力された数字の数だけ、行を追加する(GAS)
③Enable QuickEditで編集

では、具体的な実装方法を解説していきましょう。

今回は、見積書作成システムを例に解説していきます。

①テーブルの設定

テーブルは「見積書ヘッダ」「見積書明細」「フォーム入力」の3つを準備します。それぞのカラムは以下の通りです。

  • 見積書ヘッダ
    ID(Text)
    作成日(Date)
    見積書名(Text)

  • 見積書明細
    ID(Text)
    見積書ヘッダID(Ref)
    商品名(Text)
    単価(Price)
    個数(Number)
    単位(Text)
    v_合計(Price):単価×個数

  • フォーム入力
    ID(Text)
    見積ヘッダID(Ref)
    行数(number)

②GASの準備

GASでは以下のようなコードを書きます。

function addRows(parentId, rowCount) {
  // スプレッドシートをID指定で取得
  const ss = SpreadsheetApp.openById('〇〇〇');//あなたのスプレッドシートのIDを指定してください
  const detailSheet = ss.getSheetByName('見積書明細'); 
  const inputSheet = ss.getSheetByName('フォーム入力'); 
  
  // 引数のチェック
  if (!parentId || !rowCount || rowCount <= 0) {
    console.log("無効な引数です: parentId=" + parentId + ", rowCount=" + rowCount);
    return;
  }

  // 追加するデータを配列で作成
  const newRows = [];
  for (let i = 0; i < rowCount; i++) {
    // A列:UUID, B列:見積ヘッダID, C列以降:空文字
    newRows.push([Utilities.getUuid(), parentId, "", "", "", ""]); 
  }

  // 1. 見積書明細へ一括書き込み
  if (newRows.length > 0) {
    detailSheet.getRange(detailSheet.getLastRow() + 1, 1, newRows.length, newRows[0].length).setValues(newRows);
  }

  // 2. フォーム入力の2行目(処理したレコード)を削除
  // データがある場合のみ実行
  if (inputSheet.getLastRow() >= 2) {
    inputSheet.deleteRow(2); 
  }
}

コードの詳細は省きますが、理解する上で重要なポイントを説明します。

1.function addRows(parentId, rowCount)

parentIdとrowCountは「引数」と呼ばれるものです。

parentIdには見積書ヘッダのIDが、rowCountには指定した行数をAppSheetから入力します。

以下は、取得したparentIdとrowCountを使用して、行を追加する式です。

  for (let i = 0; i < rowCount; i++) {
    newRows.push([Utilities.getUuid(), parentId, "", "", "",""]); 
  }

例えば、parentIdに「a1234」、rowCountに「10」を入力して実行した場合、下記の様に入力されます。

見積書ヘッダIDには「a1234」が入力され、さらに指定した10行が追加されていることがわかります。

ちなみに、Utilities.getUuid()は、ランダムな文字列を自動生成する関数です。
そのため、IDの列には一意の文字列が入力されています。

2.配列による高速処理

const newRows = [];

上記のコードでは配列を使って、一括で行を追加するようにしています。

例えば、rowCountを10とした場合、1行ずつスプレッドシートに書き込む処理を10回繰り返しますが、これでは遅くなります。

そのため、10行まとめて「配列」という箱の中に格納し、スプレッドシートへの書き込みを一回にすることで、処理時間が短かくなります。

行を追加する系のコードを利用する場合は、配列を上手く使っていきましょう。

3.「フォーム入力」テーブルの2行目のクリア

  const lastRow = inputSheet.getLastRow();
  
  if (lastRow >= 2) {
    inputSheet.deleteRow(2); 
  }

フォームで保存を実行すると、既存データの上書きではなく、新規データとして追加される仕様になっています。そのため、何度も保存操作を行うと、データが次々と蓄積されていきます。

この問題を解決するため、保存処理の最後に入力値をクリアする処理を組み込み、データの重複追加を防止します。

なお、InputとUSERSETTINGS、Actionを活用した更新処理も実装可能ですが、手順が煩雑になるため、今回はGASによる「追加→削除」という処理フローを採用します。

②AppSheetの設定

次に、AppSheetの設定に移ります。ここでは、フォームの作成、Botの設定、アクションの設定の順番で行います。

フォームの準備

フォームは「SYSTEM GENERATED」で自動で作成されたものを利用します。

ここで入力した数字が、GASのコードにあった「rowCount」と「parentId」に渡され、「rowCount」分の行数が追加されます。

Botの設定

ここが最も重要です。順を追って解説していきます。

1.トリガーの設定

「Configure event」をクリックし、「Create a new event」を選択します。

「Event name」を「トリガー」、「Table」を「フォーム入力」、「Data change type」を「Adds」とします。

これは、「『フォーム入力』テーブルに行が追加されたら、次のステップを実行する」という設定です。

今回の場合、フォームから値を追加したときにGASを起動させたいので、このような設定にしています。

2.GAS起動の設定

トリガーを設定したら、次はいよいよGASとAppSheetを結びつけます。

「Add a step」をクリックし、「Create a new event」を選択します。
「Run a task」になっていることを確認し、右側ナビゲーションの「Call a script」を選択します。
「Apps Script Project」ををクリックし、先のGASファイルを選択します。(「Authorize」が出た場合は、手順に従って許可してください。)
「Function Name」から、addRows(parentId, rowCount)を選択します。

すると、Function Parametersというものが表示され、parentIdとrowCountが出てきます。これが引数であり、AppSheetからGASへ値を渡す操作です。
parentIdnidには[見積ヘッダID]を、rowCountには[行数]を入力します。

これで、フォームの保存をトリガーに、フォームに入力した見積ヘッダIDと行数が、GASに渡されて実行される、という流れができました。

アクションの設定

次に、アクションを設定します。

これは簡単で、「見積書明細」からフォームを呼び出すアクションを設定するだけです。

Do thisを「App:go to another view within this app 」とし、関数には「LINKTOVIEW("フォーム入力_Form")」を入力します。

実際の動き

では、実際に行の追加から編集までの流れを見ていきましょう。

うまくできていますね!

ちなみに、実行後のフォーム入力テーブルのデータは消えているので、併せて確認してみてください。

おわりに

以上のように、GASと既存機能をミックスすることで、Excelライクな使い方も可能になります。

欲をいえば、デフォルトの機能として実装されて欲しいですが・・・。
Enable QuickEdit 自体もまだベータ版ですので、実装はまだ先ですかね。

公式の発表を待ちたいところです。

他にも、様々な使い方を解説しているので、ぜひ参考にしてください。