アクションパラメータを利用して、スプレッドシートのデータをWeb画面に出力する

#はじめに
　以前、[こちらの記事](https://qiita.com/zigutabi/items/0809fcdc4bf5897e0681)に、スプレッドシートのデータをWeb画面に表示する方法を紹介しました。
　そして今回はアクションパラメータを用いて、出力する内容に変化が生じるものを作ってみます。

##下準備
　まずWeb画面に表示させる表を作成します。
　今回使用するデータは人気レストラン「サイゼリヤ」のホームページにある[メニュー](http://book.saizeriya.co.jp/menu2012_j/book/index.html)から引用しました。量が多くなるので省略するが、サラダ、スープ、前菜、ピザ、パスタ、ハンバーグ、デザートを何件か登録します。

|種類|商品名|値段|
|:-:|:-:|:-:|
|サラダ|彩りイタリアンサラダ|350|
|サラダ|チキンとブロッコリーサラダ|350|
|サラダ|ワカメとオクラのサラダ|350|
|サラダ|小エビのサラダ|350|
|スープ|コーンクリームスープ|150|

　本記事ではアクションパラメータで渡される値から種類を絞って出力される処理にする。 

##デフォルト状態
　次にアクションパラメータが無い状態でどのように表示されるコードを記述します。用意するのはサーバー処理を行うweb.gs(ソースコードではweb.jsと表記)とテンプレートになるindex.html、それに紐づくcommonCss.html(ソースコードではcommonCss.cssと表記)を作成します。

```Javascript:web.js
const ss = SpreadsheetApp.getActiveSpreadsheet();

const Menu = function(kind, name, cost){
  this.kind = kind;
  this.name = name;
  this.cost = cost;
}

const getMenus = () => {
  const sh = ss.getSheetByName("menu");
  const menus = sh.getRange(1, 1, sh.getLastRow(), sh.getLastColumn()).getValues();
  menus.shift();
  return menus.map(e => new Menu(e[0], e[1], e[2]));
}

function doGet() {
  const html = HtmlService.createTemplateFromFile("index");
  html.menus = getMenus();
  return html.evaluate().setTitle("Getテスト");
}
```

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <?!= HtmlService.createHtmlOutputFromFile('commonCss').getContent(); ?>
  </head>
  <body>
    <div>
      <? menus ?>
      <p>データ一覧</p>
      <table>
        <tr>
          <th>種類</th>
          <th>商品名</th>
          <th>価格</th>
        </tr>
        <? for(menu of menus){ ?>
          <tr>
            <td class="left"><?= menu.kind ?></td>
            <td class="left"><?= menu.name ?></td>
            <td class="right">\<?= menu.cost ?></td>
          </tr>
        <? } ?>
      </table>
    </div>
  </body>
</html>
```

```css:commonCss.css
<style>
  table{
    width: 30%;
    border-collapse: collapse;
  }
      
  th{
    text-align: center;
    border: 1px solid #000;
  }
      
  td{
    border: 1px solid #000;
  }
      
  .left{
    text-align: left;
  }
      
  .right{
    text-align: right;
  }
</style>
```
　この状態でWebサイトを開いてみます。
　するとスプレッドシートに表記したデータが全て表示されていることがわかります。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188968/fe1ea0b0-17cc-8f63-c1f0-cf45671e3fb8.png)

##アクションパラメータの実装
　次はアクションパラメータに応じて表示される内容が変化するコードを修正します。
　アクションパラメータはdoGetメソッドが実行された時、つまりWebサイトを開いた時に実行されます。
　なので今回はWeb.gsを以下のようなコードに修正することでアクションパラメータに応じて変化する処理が実装できます。

```Javascript:web.js
const ss = SpreadsheetApp.getActiveSpreadsheet();

const Menu = function(kind, name, cost){
  this.kind = kind;
  this.name = name;
  this.cost = cost;
}

const getMenus = (val) => {
  const sh = ss.getSheetByName("menu");
  const menus = sh.getRange(1, 1, sh.getLastRow(), sh.getLastColumn()).getValues();
  menus.shift();
  return menus.map(e => new Menu(e[0], e[1], e[2])).filter(e => e.kind === val);
}

function doGet(e) {
  // アクションパラメータから渡される値が半角数値にするため追加
  const category = {
    "1":"サラダ",
    "2":"スープ",
    "3":"前菜",
    "4":"ピザ",
    "5":"パスタ",
    "6":"ハンバーグ",
    "7":"デザート"
  }
  let param = e.parameter;
  // アクションパラメータが無い場合、デフォルト値に変換
  if(Object.keys(param).length === 0){
    param = {
      "category": 1
    };
  }

  const html = HtmlService.createTemplateFromFile("index");
  html.menus = getMenus(category[param.category]);
  return html.evaluate().setTitle("Getテスト");
}
```
　この状態でデプロイまたは「デプロイをテスト」でWeb画面を開きます。すると、Webサイト上ではデータが絞られた状態で表示されているのかと思います。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188968/cebbfa67-a65d-4447-7b41-620b0389b7b5.png)

　次にURLに以下の文字列を書き加えてブラウザを実行してみると表示されている内容が変化されていることがわかります。
```
デプロイ時に発行されるURL?category=2
```
　categoryに適応させている値を1～7の間で書き換えると表示される内容が変化したのが確認できたかと思います。

##Formの追加
　前項では直接URLを変更することで画面表示を切り替えましたが、こちらは正当な方法とはいえません。というのもアクションパラメータを実践で運用する際には複数個有り、中にはハッシュ関数を用いて本来の値が外部にわからないように加工するからである。
　なのでここではForm要素を追加することでURLを直接弄ることなく、アクションパラメータを付与する方式を取りたいと思います。

```Javascript:web.js
const ss = SpreadsheetApp.getActiveSpreadsheet();

const Menu = function(kind, name, cost){
  this.kind = kind;
  this.name = name;
  this.cost = cost;
}

const getMenus = val => {
  const sh = ss.getSheetByName("menu");
  const menus = sh.getRange(1, 1, sh.getLastRow(), sh.getLastColumn()).getValues();
  menus.shift();
  return menus.map(e => new Menu(e[0], e[1], e[2])).filter(e => e.kind === val);
}

// URLを動的に取得
const getMyUrl = () =>{
  return ScriptApp.getService().getUrl();
}

function doGet(e) {
  // アクションパラメータから渡される値が半角数値にするため追加
  const category = {
    "1":"サラダ",
    "2":"スープ",
    "3":"前菜",
    "4":"ピザ",
    "5":"パスタ",
    "6":"ハンバーグ",
    "7":"デザート"
  }
  let param = e.parameter;
  // アクションパラメータが無い場合、デフォルト値に変換
  if(Object.keys(param).length === 0){
    param = {
      "category": 1
    };
  }

  const html = HtmlService.createTemplateFromFile("index");
  html.menus = getMenus(category[param.category]);
  return html.evaluate().setTitle("Getテスト");
}
```

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <?!= HtmlService.createHtmlOutputFromFile('commonCss').getContent(); ?>
  </head>
  <body>
    <div>
      <form method="get" action="<?= getMyUrl() ?>">
        <select name="category">
          <option value="1">サラダ</option>
          <option value="2">スープ</option>
          <option value="3">前菜</option>
          <option value="4">ピザ</option>
          <option value="5">パスタ</option>
          <option value="6">ハンバーグ</option>
          <option value="7">デザート</option>
        </select>
        <input type="submit" value="変更">
      </form>
      <? menus ?>
      <p>データ一覧</p>
      <table>
        <tr>
          <th>種類</th>
          <th>商品名</th>
          <th>価格</th>
        </tr>
        <? for(menu of menus){ ?>
          <tr>
            <td class="left"><?= menu.kind ?></td>
            <td class="left"><?= menu.name ?></td>
            <td class="right">\<?= menu.cost ?></td>
          </tr>
        <? } ?>
      </table>
    </div>
  </body>
</html>
```
　コードを書き換えたら、前項と同じようにWeb画面を開いたら、以下のような画面が表示されているのかと思います。
　セレクトボックスの中身を変換し、ボタンをクリックすると表示される画面が切り替わります。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188968/62fc1afd-89ba-2d99-ce98-b31dd6321d8e.png)



##最後に
　今回、アクションパラメータを変化させることで出力させる内容を変化させる方法をざっくりと紹介しました。
　アクションパラメータを用いる長所はURLの内容だけで動的挙動を持たせることができることにあります。それにより軽量かつ再現性の高いWebアプリが作成できる。
　この記事では種類別で置き換えたが都道府県別や職業別等、色々と応用できる範囲は広いので、参考になれば幸いです。またフリーアカウントではできないが、Google_Workspaceの法人向けアカウントであれば同じドメインアカウント以外アクセスできない制御ができる。それを利用しアクションパラメータに直接ユーザーアカウントを埋め込むのも、社内サービスに絞れば選択肢に加えることができる。

　もし理解不足な点がみられたら、ご指摘頂けると幸いです。