スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた２

#はじめに
前回のこちらの[スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた](https://qiita.com/yamamow/items/ec8d2de7773d55345c1a) から機能を増やしてみた。

#追加した内容
1. CSSでなんとなく整形した
1. selectタグを使えるようにした
1. radioボタンを使えるようにした
1. チェックボックスを使えるようにした

もちろん新規登録、編集にも対応させている。
まず、どんな画面になったか見ていただいたほうがいいですね。
一覧画面はこちら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207568/f7538a7b-f7aa-1287-9f75-51e089fb2732.png)

編集画面はこちら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207568/04394316-6906-ff11-ee55-1b59499a3b5b.png)

少し見栄えもよくなって、
「県」がselectなり、「営業時間」がラジオボタン、「設備」がチェックボックスになっていますね。
細かく見ていきましょう。

# ①CSSの追加
GASでは「.css」としては作成できず、すべて「.html」となるので、
今回は「css.html」として作成した。
そして、「コード.gs」内にインクルードする関数を追加↓

```javascript
function include(filename) {
  return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
```
そして、各htmlファイルのheadタグに以下を追加しCSSファイルを読み込ませる

```javascript
<?!= include('css'); ?>
```
これでCSSファイルの共有が行える。
css.htmlの中は、「style」タグで囲う。
今回は作成しないが、jsファイルを読み込ませたい場合も同じように作成しincludeする。
jsファイルの中も、「script」タグで囲ったほうがいいと思う。

# ②データシートの修正
selectタグや、radioボタン、チェックボックスを使えるようにするため、データシートの構成を変更した。
使える種別は以下とした。

|種別設定|設定内容|凡例|
|:---|:---|:---|
|read|なし||
|text|テキストの長さ|８|
|textarea|テキストエリアの行数と長さ|3,30|
|radio|参照シートの列番号|2|
|checkbox|参照シートの列番号|3|
|select|参照シートの列番号|4|

前回は、１行目に項目名だけだったが
今回は、２行目に上記のselectタグや、radioボタン、チェックボックスなどの種別
　　　　３行目にそれらの設定値を入れることとした。

そのため、データは４行目からとなる。
そして、「itemmaster」というシートを１枚追加した。
selectタグや、radioボタン、チェックボックスなどの見出しとなるデータを記載するシートになる。

２行目が「text」や「textarea」なら、３行目はそのテキストの長さを設定する値を入力する。
２行目が、「select」や「radio」、「checkbox」なら、３行目は、「itemmaster」シートの**何列目か**を参照するための数値を設定する仕掛けとした。

つまり、データシートの
１行目に、「都道府県」と入力
２行目に、「select」を設定
３行目に、「2」　を設定（※「itemmaster」シートの２列目を参照の意味）

|行番号|入力値|
|:---|:---|
|１行目|都道府県|
|２行目|select|
|３行目|2|


そして、「itemmaster」シートの「２列目」の
１行目には、人間が分かりやすくするために「都道府県」と入力しておく。
（ここを参照しているんだなと、見た目で分かるようにするため）
そして、表示するデータを入れていく
２行目には、「北海道」
３行目には、「青森県」
４行目には、「岩手県」
５行目には、「宮城県」

itemmasterシートの「**２列目**」には以下のように記載する。

|行番号|入力値|
|:---|:---|
|１行目|都道府県|
|２行目|北海道|
|３行目|青森県|
|４行目|岩手県|
|５行目|宮城県|

# ③その他　細かい修正
## その１　
データの項目名の取得を３行目まで拡大した。
前途の通り、設定内容を取得するため。

## その２
index.htmlは参照表示しているだけなので変更はないが、
更新画面(edit.html）と、新規登録画面（new.html）（※前回とファイル名が違うかもm(＿'＿)m）
も前途の通り設定内容を反映するため大幅に変更している。

# selectとcheckboxのデータの持ち方のお話
**「DB代わりに」**って謳っているんだから、正規化しないの？とか言われちゃいそうですが・・・
はい、今回は正規化しないでやっております。（めちゃくちゃ煩雑＆難しい＆難しそうなので）
で、どうやって持つんだという話ですが、
「設備関係」のチェックボックスがあって「駐車場あり」、「駐輪場あり」の両方にチェックをつけたとします。
その場合は、「駐車場あり,駐輪場あり」のように、文字列で持ち、カンマ区切りとしました。
（はいそうです。チェックボックスなどの見出しの中にカンマは入れないでください。）

# selectとcheckboxのデータの表示のお話
そんなわけで、select、raidio、checkboxなどによってHTMLの書き出しを分けたので
だいぶお見苦しいソースになってしまいました.......

# とりあえずソース
今回はcssが増えたので、全部で５ファイルになります。
あとdatabaseシート　と　itemmasterシート　のデータですね。

・databaseシート
今回は少なめに表示。
一応断っておきますが、実際の店舗に行った感想ではありませんし、適当に入れたデータなので、そこんところよろしくお願いします。吉野家がうまいのは事実です。はい。

```
リンク,タイムスタンプ,店舗名,郵便番号,県,住所,電話番号,営業時間,設備,感想
read,read,text,text,select,textarea,text,radio,checkbox,textarea
,,30,8,2,"5,30",15,3,4,"3,30"
4,2020/04/22 15:00:14,吉野家 有楽町１号店,100-0006,東京都,千代田区有楽町2丁目,,９－２１時かも,"駐車場,駐輪場",とってもいい                            
5,2020/02/08 14:57:55,吉野家 有楽町２号店,100-0006,東京都,千代田区有楽町2丁目,,９－２１時かも,"駐車場,駐輪場",うまい
6,2020/02/09 14:57:55,吉野家 永田町１号店,100-0014,東京都,千代田区永田町1丁目,,９－２１時かも,"駐車場,駐輪場",うまーい
7,2020/02/10 14:57:55,吉野家 水道橋１号店,101-0061,東京都,千代田区神田三崎町2丁目,,９－２１時かも,"駐車場,駐輪場",とってもいい                            
8,2020/02/11 14:57:55,吉野家 小川町１号店,101-0052,東京都,千代田区神田小川町2丁目,,９－２１時かも,"駐車場,駐輪場",うまい
9,2020/02/12 14:57:55,吉野家 秋葉原１号店,101-0023,東京都,千代田区神田松永町,,,"駐車場,駐輪場",うまーい
10,2020/02/13 14:57:55,吉野家 神保町１号店,101-0051,東京都,千代田区神田神保町2丁目,,,"駐車場,駐輪場",
11,2020/02/14 14:57:55,吉野家 淡路町１号店,101-0041,東京都,千代田区神田須田町1丁目,,,"駐車場,駐輪場",
12,2020/02/15 14:57:55,吉野家 お茶の水１号店,101-0062,東京都,千代田区神田駿河台2丁目,,,"駐車場,駐輪場",
13,2020/02/16 14:57:55,吉野家 神田１号店,101-0044,東京都,千代田区鍛冶町2丁目,,,"駐車場,駐輪場",
14,2020/02/17 14:57:55,吉野家 霞ヶ関１号店,100-8918,東京都,千代田区霞が関,,,ドライブスルーかも,
15,2020/02/18 14:57:55,吉野家 霞が関２号店,100-0013,東京都,千代田区霞が関,,,ドライブスルーかも,
16,2020/02/19 14:57:55,吉野家 帯広１号店,080-0011,北海道,帯広市西1条南,,,ドライブスルーかも,	
```
・itemmasterシート
都道府県があるので長いですが、サンプルってことで。

```
表示形式,県リスト,営業時間,設備
read,北海道,24時間かも,駐車場
text,青森県,９－２１時かも,駐輪場
textarea,岩手県,,ドライブスルーかも
select,宮城県,,
radio,秋田県,,
checkbox,山形県,,
,福島県,,
,茨城県,,
,栃木県,,
,群馬県,,
,埼玉県,,
,千葉県,,
,東京都,,
,神奈川県,,
,新潟県,,
,富山県,,
,石川県,,
,福井県,,
,山梨県,,
,長野県,,
,岐阜県,,
,静岡県,,
,愛知県,,
,三重県,,
,滋賀県,,
,京都府,,
,大阪府,,
,兵庫県,,
,奈良県,,
,和歌山県,,
,鳥取県,,
,島根県,,
,岡山県,,
,広島県,,
,山口県,,
,徳島県,,
,香川県,,
,愛媛県,,
,高知県,,
,福岡県,,
,佐賀県,,
,長崎県,,
,熊本県,,
,大分県,,
,宮崎県,,
,鹿児島県,,
,沖縄県,,
```
・コード.gs

```javascript
//スプレッドシートの項目が増えた場合、以下の関数を修正してください。
function getParameter(ary1, e) {
  // -----------------------------------------------------------------------
  //項目が増えたら増やす ーーーーーーーーーーA列は行数（※固定）、B列はタイムスタンプ（※固定）
  ary1.push(e.parameters.d_item2); //C列
  ary1.push(e.parameters.d_item3); //D列
  ary1.push(e.parameters.d_item4); //E列
  ary1.push(e.parameters.d_item5); //F列
  ary1.push(e.parameters.d_item6); //G列
  ary1.push(e.parameters.d_item7); //H列
  ary1.push(e.parameters.d_item8); //I列
  ary1.push(e.parameters.d_item9); //J列
    
  // -----------------------------------------------------------------------
  return ary1;
}

function doGet(e) {
  //初期表示かlistの時
  if (e.parameter.mode == 'list' || e.parameter.mode == null) {
    var template = HtmlService.createTemplateFromFile('index');
    var ItemNameList = getItemNameList(6);
    tmp1 = getNewDataList();
    var res3 = [];
    for(var i = 0; i < tmp1.length; i++){
      res3.push(getCellValue(tmp1[i][0], 6));
    }
    template.res = res3;
  } 
  //新規か編集の時
  if (e.parameter.mode == 'new' || e.parameter.mode == 'edit') {
    var template = HtmlService.createTemplateFromFile(e.parameter.mode);
    var ItemNameList = getItemNameList(-1);
    for (var i = 0; i < ItemNameList[1].length; i++){
      Logger.log(ItemNameList[1][i]);
      if (ItemNameList[1][i] == 'select' || ItemNameList[1][i] == 'radio' || ItemNameList[1][i] == 'checkbox') {
        var tmp1 = getMasterData(ItemNameList[2][i]); 
        ItemNameList[2][i] = tmp1; 
      }
    }
  }
  //編集時は更に
  if (e.parameter.mode == 'edit') {
    var editRow = e.parameter.row;
    template.row = editRow;
    template.res = getCellValue(editRow, -1);
  }
  
  template.itemName = ItemNameList;
  return template.evaluate();
}

//主にCSSをインクルードするためのもの
function include(filename) {
  return HtmlService.createHtmlOutputFromFile(filename).getContent();
}

function doPost(e) {
  //Logger.log('doPost');
  var spread = SpreadsheetApp.getActiveSpreadsheet() ;
  var sheet = spread.getSheetByName('database');
  var date = new Date();
  // 今日の日付を表示
  date1 = Utilities.formatDate( date, 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss');
  //すべて処理後は一覧表示するのでindexを指定
  var template = HtmlService.createTemplateFromFile('index');
  var ItemNameList = getItemNameList(6);             //★6列を指定
  template.itemName = ItemNameList;  
  
  //編集時
  if (e.parameter.mode == 'edit') {
    Logger.log('編集時');
    var ary1 = [];
    var d_row = e.parameters.d_item0;
    ary1.push(d_row);
    ary1.push(date1);
    ary1 = getParameter(ary1, e);
    var ary2 = [];
    ary2.push(ary1);
    var ary3 = [];
    ary3 = shapParameter(ary2); //チェクボックスなどのデータ加工
    //保存
    dataSave(sheet, d_row,1,1,ary2[0].length, ary3);
    
    //一覧表示
    tmp1 = getNewDataList();
    var res3 = [];
    for(var i = 0; i < tmp1.length; i++){
      res3.push(getCellValue(tmp1[i][0], 6));
    }
    template.res = res3;
    
　//新規作成時
  }else if (e.parameter.mode == 'new') {
    Logger.log('新規作成時');
    
    var ary1 = [];
    ary1.push(sheet.getLastRow()+1);
    ary1.push(date1);
    ary1 = getParameter(ary1, e);
    var ary2 = [];
    ary2.push(ary1);
    var ary3 = [];
    ary3 = shapParameter(ary2); //チェクボックスなどのデータ加工
    //保存
    dataSave(sheet, sheet.getLastRow()+1, 1, 1, ary2[0].length, ary2);
   
    //一覧表示
    tmp1 = getNewDataList();
    var res3 = [];
    for(var i = 0; i < tmp1.length; i++){
      res3.push(getCellValue(tmp1[i][0], 6));
    }
    template.res = res3;
  
  //検索時 
  } else {
    var res2 = rowSearch(e.parameter.search);
    var res3 = [];
    for(var i = 0; i < res2.length; i++){
      res3.push(getCellValue(res2[i], 6));
    }
    //<?= res ?> がHTMLにあること
    template.res = res3;
  }  
  return template.evaluate();
}

//データを加工する
//チェックボックスのデータをカンマ区切りの文字列として加工する
function shapParameter(ary) {
  Logger.log('shapParameterX');
  var itemNameA = getItemNameList(-1);
  for (var i = 0; i < itemNameA[1].length; i++) {
    Logger.log(itemNameA[1][i]);
    if (itemNameA[1][i] == 'checkbox'){
      ary[0][i] = ary[0][i].join();      
    }
  }
  return ary;
}

//マスターデータを取得
function getMasterData(col) {
  var spread = SpreadsheetApp.getActiveSpreadsheet() ;
  var sheet = spread.getSheetByName('itemmaster');
  var values = sheet.getRange(2, col, sheet.getRange(2, col).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()-1, 1).getValues();
  Logger.log('Masterデータを取得');
  Logger.log(values);
  return values;
}

//更新や新規登録を行う
//排他制御を掛けるので更新処理を一か所にまとめた
function dataSave(sheet, row1, col1, row2, col2, data){
  var msg = "";
  
  //ドキュメントロックを使用する
  var lock = LockService.getDocumentLock();
 
  //30秒間のロックを取得
  try {
    //ロックを実施する
    lock.waitLock(30000);
    
    Logger.log('data');
    Logger.log(data);
    
    //ここにメインルーチンを記述する
    sheet.getRange(row1, col1, row2, col2).setValues(data);
    
    //メッセージを格納
    msg = "保存完了";
    
  } catch (e) {
    //ロック取得できなかった時の処理等を記述する
    var checkword = "ロックのタイムアウト: 別のプロセスがロックを保持している時間が長すぎました。";
    
    //通常のエラーとロックエラーを区別する
    if(e.message == checkword){
      //ロックエラーの場合
      msg = "更新処理中でした";
    }else{
      //ソレ以外のエラーの場合
      msg = e.message;
    }  　 
    
  }　finally　{
    //ロックを開放する
    lock.releaseLock();
    
    //メッセージを表示する
    //ui.alert(msg);
  }
}


//項目名称を取得する
function getItemNameList(col){
  var res = [];
  var spread = SpreadsheetApp.getActiveSpreadsheet() ;
  var sheet = spread.getSheetByName('database');
  if (col == -1) {
    var values = sheet.getRange(1, 1, 3, sheet.getLastColumn()).getValues();
  } else {
    var values = sheet.getRange(1, 1, 1, col).getValues();
  }
  Logger.log('values getItemNameList');
  Logger.log(values);
  return values;
}

//タイムスタンプの新しい１０件を取得する。[行番号,日付]の二次元配列で時間で降順
//スプレッドシートの左から６列までとする
function getNewDataList(){
  var res = [];
  var spread = SpreadsheetApp.getActiveSpreadsheet() ;
  var sheet = spread.getSheetByName('database');
  //2,3行目にHTMLのタグのタイプ、設定値を入れたので４行目からの取得とする
  var values = sheet.getRange(4, 1, sheet.getLastRow()-1, 2).getValues();
  //ソート　sorting_asc　sorting_desc
  values.sort(sorting_desc);
  for (var i = 0; i < 10; i++){
    res.push(values[i]);
  }
  return res;
}

//スプレッドシート内を文言で検索し行番号を返す（同じ行内に複数出てくると抽出結果も重複する
function rowSearch(str){
  var res = [];
  var spread = SpreadsheetApp.getActiveSpreadsheet() ;
  var sheet = spread.getSheetByName('database');
  var textFinder = sheet.createTextFinder(str);
  var ranges = textFinder.findAll();
  for(var i = 0; i < ranges.length; i++){
    var range = sheet.getRange(ranges[i].getA1Notation());
    res.push(range.getRow());
  }
  var res2 = uniqueArray(res);

  return res2;
}

//行番号からセル値を取得
function getCellValue(row, col){
  // 現在アクティブなスプレッドシートを取得
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('database');
  // そのシートにある (1, 1) のセルから3行目までのセル範囲を取得
  if (col == -1 ) {
    var range = sheet.getRange(row, 1, 1, sheet.getLastColumn());
  } else {
    var range = sheet.getRange(row, 1, 1, col);
  }
  // そのセル範囲の値を取得
  var values = range.getValues(); 
  values[0][0] = row;
  values[0][1] = Utilities.formatDate( values[0][1], 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss');
  
  return values[0];
}

//一次配列から重複を排除する
function uniqueArray(ary){
  var res = [];
  res = ary.filter(function(value, index, self){ 
                       return self.indexOf(value) === index;
                   });
  return res;
}
//ソート昇順
function sorting_asc(a, b){
  if(a[1] < b[1]){
    return -1;
  }else if(a[1] > b[1] ){
    return 1;
  }else{
   return 0;
  }
}
//ソート降順
function sorting_desc(a, b){
  if(a[1] > b[1]){
    return -1;
  }else if(a[1] < b[1] ){
    return 1;
  }else{
   return 0;
  }
}

```
・index.html

```html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <?!= include('css'); ?>
  </head>
  <body>
    <form method="post" action='https://script.google.com/macros/s/ここに公開時のURLを記載する/exec'>
    <div>
      <input type=hidden name=mode value='list' />mode: list
      <h2>吉野家一覧画面</h2>
      初期表示は、スプレッドシートの２列目のタイムスタンプで最新の１０行、6列を表示します。<br>
      そのため、一覧表示したいものは左から６項目内にするようにします。<br>
      ただし、左の２列はそのままにしてください。よって、残りの４項目になります。（※ソースを変更すれば項目数は調整できます）<br>
      検索時は、スプレッドシート全体から対象文言を検索し、ヒットした行すべてを表示します。<br>
      スプレッドシートの項目を追加（１行目の項目名を追加）する場合は、「コード.gs」のgetParamet関数の<br>
      「//項目が増えたら増やす」の下にある書き方にならって増やしてください。<br>
      
      <br>
      新規は<a href='https://script.google.com/macros/s/ここに公開時のURLを記載する/exec?mode=new'>こちら</a><br>
      検索：<input type='text' name=search /> <input type='submit' class='btn-radius' value='検索' /><br><br>
      <table>
        <!-- 項目名を取得し、表示する   -->
        <tr>
          <? for (var h = 0; h < itemName[0].length; h++) { ?>
              <th><?= itemName[0][h] ?></th>
          <? } ?>
        </tr>
        <!-- データを取得し、表示する   -->
        <? for (var i = 0; i < res.length; i++) { ?>
        <tr>
          <? for (var j = 0; j < res[i].length; j++) { ?>
            <? if (j == 0) {   ?>
              <td><a href='https://script.google.com/macros/s/ここに公開時のURLを記載する/exec?mode=edit&row=<?= res[i][j] ?>'>編集</a></td>
            <? } else { ?>
              <td><?= res[i][j] ?></td>
            <? } ?>
          <? } ?>
        </tr>
        <? } ?>
      </table>
      </div>
    </form>
  </body>
</html>

```
・edit.html

```html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <?!= include('css'); ?>
  </head>
  <body>
    <form method="post" action='https://script.google.com/macros/s/ここに公開時のURLを記載する/exec'>
    <div>
      <input type=hidden name=mode value='edit' />mode: edit
      <h2>吉野家　編集画面</h2>
      <table>　
        <!-- 項目名を取得し、表示する   -->
        <? var iItemName = 0; ?>
        <? var sItemType = 1; ?>
        <? var sItemSetting = 2; ?>
        <? for (var h = 0; h < itemName[0].length; h++) { ?>
        <tr> 
          <th><?= itemName[0][h] ?></th>
          <? if ( h == 0 ) { ?>
            <td><input type=hidden name=d_item<?= h ?> value='<?= res[h] ?>' /><?= res[h] ?></td>
       
          <? } else if (h == 1) { ?>
            <td><input type=hidden name=d_item<?= h ?> /><?= res[h] ?></td>
            
          <? } else { ?>
            <? if (itemName[sItemType][h] == 'text') { ?>
              <td><input type=text name=d_item<?= h ?> size=<?= itemName[sItemSetting][h] ?> 
              maxlength=<?= itemName[sItemSetting][h] ?> value='<?= res[h] ?>' /></td>
              
            <? } else if (itemName[sItemType][h] == 'textarea') { 
                  var ary = itemName[sItemSetting][h].split(','); ?>
              <!-- TEXTAREAタグの間に空白を入れるとそのまま表示されるので注意 -->
              <td><textarea name=d_item<?= h ?> rows=<?= ary[0] ?> cols=<?= ary[1] ?> placeholder='ご意見をご記入ください'><?= res[h] ?></textarea></td>
              
            <!-- SELECT ------------------------------------------------------------------- -->
            <? } else if (itemName[sItemType][h] == 'select') { 
                  var ary = itemName[sItemSetting][h]; ?>
              <td><select name=d_item<?= h ?>>
              <? for (var j = 0; j < ary.length; j++) {  ?>
              
                <? if (ary[j] == res[h]) { ?>
                  <option value='<?= ary[j] ?>' selected><?= ary[j] ?></option>
                <? } else { ?>
                  <option value='<?= ary[j] ?>'><?= ary[j] ?></option>
                <? } ?>
                
              <? } ?>
              </select></td>
            <!-- SELECT --ここまで--------------------------------------------------------- -->
            
            <!-- radio ------------------------------------------------------------------- -->
            <? } else if (itemName[sItemType][h] == 'radio') { 
                  var ary = itemName[sItemSetting][h]; ?>
              <td>
              <? for (var j = 0; j < ary.length; j++) {  ?>
                <? if (ary[j] == res[h]) { ?>
                  <input type=radio name=d_item<?= h ?> value='<?= ary[j] ?>' checked="checked"><?= ary[j] ?><br>
                <? } else { ?>
                  <input type=radio name=d_item<?= h ?> value='<?= ary[j] ?>'><?= ary[j] ?><br>
                <? } ?>
              <? } ?>
              </td>

            <!-- radio --ここまで--------------------------------------------------------- -->
            
            <!-- check ------------------------------------------------------------------- -->
            <? } else if (itemName[sItemType][h] == 'checkbox') { 
                  var strCheckBox = itemName[sItemSetting][h].toString(); 
                  var ary = strCheckBox.split(",");         
                  var ary_res = (res[h].toString()).split(",");
                  ?>
              <td>
              <? for (var j = 0; j < ary.length; j++) {  ?>
                <? var ijudge = 0;
                   for (var k = 0; k < ary_res.length; k++) { 
                       if (ary[j] == ary_res[k]) {
                           ijudge = 1;
                       }
                   } ?>
                <? if (ijudge == 1) { ?>
                  <input type=checkbox name=d_item<?= h ?> value='<?= ary[j] ?>' checked="checked"><?= ary[j] ?><br>
                <? } else { ?>
                  <input type=checkbox name=d_item<?= h ?> value='<?= ary[j] ?>'><?= ary[j] ?><br>
                <? } ?>
                  
              <? } ?>
              </td>

            <!-- check --ここまで--------------------------------------------------------- -->

            <? } ?>   <!-- else if を閉じる -->
          <? } ?>
        </tr>
        <? } ?>
      </table>
      <input type='submit' class='btn-radius' value='更新' /><br>
      <a href='https://script.google.com/macros/s/ここに公開時のURLを記載する/exec?mode=list'>検索ページへ</a>
      </div>
    </form>
  </body>
</html>



```
・new.html

```html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <?!= include('css'); ?>
  </head>
  <body>
    <form method="post" action='https://script.google.com/macros/s/ここに公開時のURLを記載する/exec'>
    <div>
      <input type=hidden name=mode value='new' />mode: new
      <h2>吉野家　登録画面</h2>
      <table>　
        <!-- 項目名を取得し、表示する   -->
        <? var iItemName = 0; ?>
        <? var sItemType = 1; ?>
        <? var sItemSetting = 2; ?>
        <? for (var h = 0; h < itemName[0].length; h++) { ?>
        <tr> 
          <th><?= itemName[iItemName][h] ?></th>
          <? if ( h == 0 ) { ?>
            <td><input type=hidden name=d_item<?= h ?> /></td>
       
          <? } else if (h == 1) { ?>
            <td><input type=hidden name=d_item<?= h ?> /></td>
          
          <? } else { ?>
          
            <? if (itemName[sItemType][h] == 'text') { ?>
              <td><input type=text name=d_item<?= h ?> size=<?= itemName[sItemSetting][h] ?> maxlength=<?= itemName[sItemSetting][h] ?> /></td>
            
            <? } else if (itemName[sItemType][h] == 'textarea') { 
                  var ary = itemName[sItemSetting][h].split(','); ?>
              <td><textarea name=d_item<?= h ?> rows=<?= ary[0] ?> cols=<?= ary[1] ?> placeholder='ご意見をご記入ください'></textarea></td>
            
            <? } else if (itemName[sItemType][h] == 'select') { 
                  var ary = itemName[sItemSetting][h]; ?>
              <td><select name=d_item<?= h ?>>
              <? for (var j = 0; j < ary.length; j++) {    ?>
                <option value='<?= ary[j] ?>'><?= ary[j] ?></option>                
              <? } ?>
              </select></td>
            
            <!-- radio ------------------------------------------------------------------- -->
            <? } else if (itemName[sItemType][h] == 'radio') { 
                  var ary = itemName[sItemSetting][h]; ?>
              <td>
              <? for (var j = 0; j < ary.length; j++) {  ?>
                  <input type=radio name=d_item<?= h ?> value='<?= ary[j] ?>'><?= ary[j] ?><br>
              <? } ?>
              </td>
            <!-- radio --ここまで--------------------------------------------------------- -->
            
            <!-- check ------------------------------------------------------------------- -->
            <? } else if (itemName[sItemType][h] == 'checkbox') { 
                  var strCheckBox = itemName[sItemSetting][h].toString(); 
                  var ary = strCheckBox.split(",");         
                  ?>
              <td>
              <? for (var j = 0; j < ary.length; j++) {  ?>
                  <input type=checkbox name=d_item<?= h ?> value='<?= ary[j] ?>'><?= ary[j] ?><br>
              <? } ?>
              </td>
            <!-- check --ここまで--------------------------------------------------------- -->

            <? } ?>   <!-- else if を閉じる -->
          <? } ?>
        </tr>
        <? } ?>
      </table>
      <input type='submit' class='btn-radius' value='登録' /><br>
      <a href='https://script.google.com/macros/s/ここに公開時のURLを記載する/exec?mode=list'>検索ページへ</a>
    </div>
    </form>
  </body>
</html>

```
・css.html

```html
<style>
body{
    font-family:Verdana,Arial;
    font-size:16px;
    text-align: center; 
}

div{
    text-align:center;
    margin-left:auto;
    margin-right:auto;
    text-align:left;
    width: 80%;
}

h2{
    font-size:16px;
    border-left:5px solid #ccc;
    padding:3px 0 3px 10px;
    margin-bottom:10px;
}

h3{
    border-bottom:1px solid #ccc;
    padding:3px 0;
    margin-bottom:10px;
}

table{
  border-collapse:separate;
  border-spacing: 0;
}

table th{
  text-align: center;
  color:white;
  background: linear-gradient(#829ebc,#225588);
  border-left: 1px solid #3c6690;
  border-top: 1px solid #3c6690;
  border-bottom: 1px solid #3c6690;
  box-shadow: 0px 1px 1px rgba(255,255,255,0.3) inset;
  padding: 10px 10px;
}

table td{
  text-align: center;
  border-left: 1px solid #a8b7c5;
  border-bottom: 1px solid #a8b7c5;
  border-top:none;
  padding: 10px 10px;
}

table tr:nth-child(odd){
  background-color: #eee
}

table td:last-child{
  border-right: 1px solid #a8b7c5;
}

.btn-radius {
  display: inline-block;
  padding: 7px 20px;
  border-radius: 25px;
  text-decoration: none;
  color: #FFF;
  background-image: linear-gradient(45deg, #FFC107 0%, #ff8b5f 100%);
  transition: .4s;
}

.btn-radius:hover {
  background-image: linear-gradient(45deg, #FFC107 0%, #f76a35 100%);
}
</style>
```

ここまでお付き合いいただきありがとうございました。
なにか参考になれば幸いです。

でわでわ。

追記：
　Vue版を作ってみました。
　ご興味のある方は是非。
　[スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版その１～～](https://qiita.com/yamamow/items/6be4fa99cd3cb45ecffa)