01_WEBアプリ基本

【01_WEBアプリ基本】テーブル形式フォーム〔解説編Vol.4〕編集したテーブルの値をたった1行のコードでサーバに送り、スプレッドシートに保存する

記事概要

前の記事まででスプレッドシートの値をテーブルに表す方法を説明しました。しかしテンプレート上に表示させたセルの値は編集可能であるものの、ブラウザを閉じると消えてしまいます。
編集結果を残すには、WEBのページ上の値をサーバに送って、スプレッドシートに保存する必要があります。しかし、クライアントPC(ユーザーのPC)からサーバへのデータ送信はなかなか厄介で、WEBアプリを開発するハードルの一つになっています。
 ところが、GAS(Google Apps Script)ならたった1行のコードでできてしまいます。

この説明はテンプレートファイルになります。(プロジェクトでHTMLの方を選択してください) 

WEB画面上のテーブルの編集結果は、ブラウザを閉じると消えてしまう

テンプレート上に表示させたテーブルのセルは、<td contenteditable=”true”>というタグにすることで編集可能になっていますので参照だけでなく、編集も可能です。

例えば、下の様なテーブルを編集して・・・

画像1
4行目を追加し、3行目の値段を訂正したとします。
画像2

テーブルは、各ユーザーのブラウザ上でのみ存在しているので、ブラウザを閉じると編集データは消えてしまいます。

編集結果を残すには、元のスプレッドシートへのデータの保存が必要です。その為には、現時点でのクライアントPCで表示されているテーブル上のデータを収集して、サーバー側に引き渡す必要があります。

Google.script.run 関数・・・POST処理など実装不要、GASならたった1行のコードでサーバにデータ送信できる

ここの説明はテンプレートファイルになります。(プロジェクトでHTMLの方を選択してください) 
画像3

クライアントPC上にあるデータをサーバに引き渡す時によく使用されるのがPOST処理と呼ばれる方法です。GASではこれに代わる方法としてGoogle.script.runという関数(メソッド)が用意されています。

google .script .run. スクリプト内関数名(引数)
テンプレート内で上記のコードを記載しておくと、スクリプト(gs)側でも同じ名前の関数を記載しておくだけで、引数が自然と引き渡されて処理されます!

 大変簡単で便利です。

これはAjax (Asynchronous JavaScript + XML)というユーザーPCとサーバーの通信方法を利用しているのですが、これだけの手続きで実装出来てしまうのは、相当驚異的なことだと私は思います。

まずテーブル上の最新データを取得して配列に保存する

プログラムの実装では、テーブル上のデータをスプレッドシートに送る前準備として、テーブル上の最新データを取得して配列に保存します。

この処理はテンプレート内に書いた<script>タグ の間に適当な名前の関数として記述しておき、ユーザがボタンを押したタイミングで実行させる様にします。

ここの記述は通常のHTML上のスクリプトで、GASの専用仕様のインラインスクリプトではありません。
 ここでは一連の処理を doWriteSheet(myRows, myCols)関数 として定義しました。以下はその内容です。
<script>
//関数の宣言
function doWriteSheet(myRows, myCols){

//テーブルの取得

var myTable = document.getElementById(‘TableBody‘);

//テーブルの行数、列数の宣言

var nRow = myRows;
var nCol = myCols;

//テーブルの行数だけ要素のある・配列を宣言

var myCells = new Array(nRow);

//テーブルの列数だけ子要素を宣言

for (var iRow = 0; iRownRow; iRow++){
myCells[iRow] = new Array(nCol);
}
//テーブルのrowsコレクションで行数を取得| 各行でループ

for (var iRow = 0 ; iRowmyTable.rows.length; iRow++) {
//iRow行のcellsコレクションで列数を取得| 各列でループ

for (var iCol=0 ; iColmyTable.rows[iRow].cells.length; iCol++) {
・・//iRow行目のiCol列目のセルのテキスト値を取得

myCells[iRow][iCol] = myTable.rows[iRow].cells[iCol].textContent;
 }
}

//★★テーブルのセルの値をGASのSetSheet 関数に渡し、成功したらonSuccessを実行★★

google.script.run.withSuccessHandler(onSuccess).SetSheet(myCells, nRow, nCol);
}
</script>

プログラムのキーになるところは以下です。

テーブルオブジェクトを取得
  var テーブル配列 = document.getElementById(‘テーブルのID‘);
セルの値を保存する配列の用意(forループで行x列だけ指定)
  var セル配列 = new Array(必要行数);
  varセル配列[各行]= new Array(必要列数);
セルの値を配列に保存(forループで行x列だけ指定)
  配列[行][列] = テーブル配列.rows[iRow].cells[iCol].textContent;
テーブルオブジェクトを取得し、セルの値を保存する変数に引き渡しています。
セル配列[各行][各列]が2重のArrayで定義されている点に注意してください。[/jin-iconbox01]
最後の行 google.script.run.withSuccessHandler(onSuccess) は次の節でご説明します。

google .script .run. スクリプト内関数(引数)の使い方 ~クライアントPCからサーバへのデータの引き渡しと、サーバからの返り値の取得

再掲しますが、GASではテンプレート内(つまりクライアントPC側)で google .script .run. スクリプト内関数名(引数) 関数を使うことで、スクリプトに引数を渡した上で関数を発動(つまりサーバ側にデータを送って処理させることが)できます。
それだけではなく更に、首尾よくスクリプト内の関数が作動したら返り値を再びスクリプトに取り込む(つまりサーバ側のレスポンスをクライアントPC側に持ってくる)事もできます。
google.script.run.withSuccessHandler(成功時関数).SetSheet(引数);
それでは実装内容をみてみます。
まず、テンプレート側(クライアントPC側)です。

あっさり1行で書いています。引き渡すのは myCells(セルの値が入った配列)、nRow, (行数)、nCol(列数)の値です。
//SetSheet関数を作動させる
google.script.run.withSuccessHandler(onSuccess).SetSheet(myCells, nRow,
nCol);

テンプレート側で発動させた関数によって、スプレッドシートにアクセスする

ここからの説明は、スクリプトファイルになります。(プロジェクトでスクリプトの方を選択してください) 

画像8

次に、テンプレート側からのgoogle.script.run関数で発動するスクリプト側のSetSheet関数ですが、以下の様になります。

//HTMLテーブルの値myCellsをシートに書き込む関数
function SetSheet(myCells, myRows, myCols){

//アプリケーションを取得|スプレッドシートのIDは各自のものを記入
var myApp = SpreadsheetApp.openById(‘★スプレッドシートのID★‘);

//対象シートをシートの名前を指定して取得
var mySheet = myApp.getSheetByName(‘支出’);

//データ記録範囲として、行数と列数を記載
var nRow = myRows;
var nCol = myCols;

//スプレッドシートにmyCellsの値を書き込み
for (var iRow = 0 ; iRow < nRow; iRow++) {
for (var iCol = 0 ; iCol < nCol; iCol++) {

//見出し部分は除外して書き込み
if(!(iRow == 0 || iCol == 0 || iCol == 5)){
mySheet.getRange(iRow + 1,iCol + 1,1,1).setValue(myCells[iRow][iCol]);
}
}
}

//返り値の変数を定義
var myTotal = new Array(2) ;

myTotal[0] = 0 ;
myTotal = 0 ;

<・・・中略myTotalにデータを代入・・・>

//結果を返す
return myTotal;

}

こちらのプログラムで、キーとなる部分は以下となります。

配列の値の1つをスプレッドシートの指定のセル1つに代入
  シートオブジェクト.getRange(行番号,列番号,1).setValue(配列データ[行番号][列番号]);
テンプレート側に値を返す
  return 変数 又は 配列
この関数をボタンで実行させるには以下の様にします。
関数に引き渡す値を変数とするため、インラインコード(スクリプトレット)で、表現しています。

<!—- ボタンの表記—->
<button onclick=”doWriteSheet(<?=myRows ?>, <?=myCols ?>)”>書込み</button>

・・

画面上では以下の様に見えます。
・ああああああああ

画像14

サーバで発動させた関数の返り値のテンプレートでの処理

ここの説明は再びテンプレートファイルになります。(プロジェクトでHTMLの方を選択してください)
画像3

最後に帰ってきた返り値の処理は、以下となります。

<script>
//GASの関数が成功したら実行する
function onSuccess(res){

//メッセージのテキストを取得する

var msg = document.getElementById(“msg”);//メッセージのテキストの中身を変更する
msg.textContent = ‘書き込みました。現在、購入数:’ + res[0] + ‘個、合計金額:’ + res+ ‘円 です。’;
}
</script>

こちらのキーポイントは以下です。

スクリプト側で関数が問題なく作動した時に実行する関数:google.script.run.withSuccessHandler(成功時関数)
  function 成功時関数(res){ 処理 }
  res:返り値
また、WEB上のテキストをこのタイミングで変えるには以下の様にします。
WEB上のテキスト
  テキストのオブジェクト.textContent = ‘書き込むテキスト’
実行してスクリプトが正しく作動すると、処理が終わると、

以下の様なテキストが・・・

画像17

 

 

 

こんな風になっています。

画像17

スプレッドシートが更新された事を確認してみよう

それでは、GASのリンクを開いて実行させ、テーブルを以下の様に編集してみましょう。表の下のボタンを押すと・・・

画像18

元はこんなスプレッドシートが・・・

画像19

処理後はこんな風に更新されています!

画像20

見事!結果が反映されました!

この段階で、スプレッドシート側で最後の列に表示されている累計値は、テンプレートには反映されていません。この最新状態はテンプレートを一旦閉じて再び開いて初めて反映されます。(下図)
画像21

結び

お疲れ様でした。ここで解説記事を終わります。

スプレッドシートのデータを、テーブル形式のフォームを使ってWEBサイトとして表示させ、編集結果を再びスプレッドシートにもどす方法について、まとまった情報があまり見当たらなかったので、書いてみました。

実際に何かに使う場合は、スプレッドシートやGASを公開した上で、セキュリティー対策や、不注意による上書きエラー対策などが必要になります。

GASの素晴らしいところは、特別にサーバやAPIを用意せずに、サーバとユーザーPCとの間でインタラクティブなWEBページが作れるところです。また、処理の一部をスプレッドシートの関数に行わせることでプログラム側の負担を軽減できる点も素晴らしい点です。

こうしたインタラクティブなWEBページはWEBアプリといわれ、特別なインストール作業なしにリンクを開くだけで使えるソフトウェアとして、現在様々なところで活躍しています。

コード全体はこちらの記事の末尾に記載しておりますので、宜しければスプレッドシートをご用意した上で、コピーして試してみてください。(ただし著作権は放棄していません。この記事の紹介のためのリンクは自由ですが、コードそのものの転載や配布はしないでください。)

書き込むシート名は「支出」とし、またプログラム中でスプレッドシートのIDを各自のものに打ち換えるのを忘れないでください。