GASでWebアプリ｢映画鑑賞記録｣を作る① ／ ExcelファイルをWebアプリに変換する（前編）

# 最初に
　勉強の為に、GASでWebアプリを作ろっと思って題材を考えていたら、趣味の映画鑑賞の記録をつけているので、これにしようと思いました。
　記録を入力するのも、後回しにすると忘れてしまったりするので、鑑賞後にその場で入力できれば忘れる事も防げますし、将来的には鑑賞後のメモを入力できる様にすれば、後からレビューを書くときの助けにもなると思います。

# 現状（Excelファイル）
　Webアプリにしようとしている元ネタは、Excel（映画鑑賞記録.xlsx）で管理しています。
　内容を簡単に説明します。
#### ［鑑賞履歴］シート
![鑑賞履歴.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510221/ae0db18a-56bc-a6fd-99e0-dfe402cadadb.png)
　このシートが、鑑賞記録そのものと成ります。

1. 「ID」は、ユニークな連番です。
1. 「鑑賞日」は、そのままですが、管理が悪くて実際の日付にはなっていません。 :sweat_smile: :sweat_drops: 
1. 「タイトル」も、そのままです。
1. 「初見」は、初めて観た場合に`1`をセットします。（既に鑑賞した事がある場合は`0`）
1. 「鑑賞種別」は、鑑賞方法により区分をセットします。（※［鑑賞種別］シートを参照）
1. 「映画館名」は、基本的（「鑑賞種別」=`1`の場合）に鑑賞した映画館の名前をセットします。

#### ［映画館］シート
![映画館.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510221/5475b119-dde0-d17b-388c-b763cecd7797.png)

1. 「映画館名」は、［鑑賞履歴］シートの「映画館名」と同じ。
1. 「鑑賞種別」は、［鑑賞履歴］シートの「鑑賞種別」と同じ。
1. 「初」は、初めて行った映画館の場合に`1`をセットします。年末にその年に初めて行った映画館を知るために使っています。なので、年始に全てのデータに`0`をセット（クリア）します。    
このリストに追加されている映画館は、既に行った事のある映画館と言う事になります。   
「鑑賞種別」≠`1`の場合は、対処外として`9`をセットします。

#### ［鑑賞種別］シート
![鑑賞種別.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510221/1e7f9904-22d2-244f-29f9-1cb57c2c1c20.png)

1. 「ID」は、鑑賞方法の区分を表します。（［鑑賞履歴］シートの「鑑賞種別」にセットする値）
1. 「鑑賞種別」は、鑑賞方法を表しています。
   - `映画館`　映画館で鑑賞した場合。
   - `DVD` 　　DVD、Blu-ray Disc、ビデオテープ等パッケージ製品で個人的に鑑賞した場合。    
　　　　「映画館名」にはレンタル会社名、パッケージの持ち主をセットする。
   - `配信`　　配信サービスで個人的に鑑賞した場合。「映画館名」にはサービス会社名をセットする。
   - `その他`　上記以外。映画館以外でのイベント上映会など。popcornでの鑑賞はコッチ。    
　　　　「映画館名」には会場名などをセットする。

# 取り敢えず一覧表示のみ
　先ず、ExcelファイルをGoogleドライブにアップロードして、スプレッドシートに変換します。（詳細は割愛します）
　次に、上記スプレッドシート（「映画鑑賞記録」）のデータを、Web画面に表示するGASのコードを用意します。
　会社内のGAS勉強会で使用したものをそのまま流用しました。（詳細については別に投稿します）
![映画鑑賞記録.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510221/065f8526-bd7d-2eed-2ac0-21f74f837851.png)
　設定ファイルやCSSの設定は別にあるのですが、メインで使用しているのは次の3ファイルのみです。

   - ViewingRecord.gs　サーバ側の処理。
   - Index.html 　　　　クライアント側の画面表示。
   - javascript.html 　　クライアント側の処理。

#### ViewingRecord.gs
```javascript
function doGet(e) {
  var template = HtmlService.createTemplateFromFile('Index');
  var title = "映画鑑賞記録";
  var html = template.evaluate().setTitle(title).setSandboxMode(HtmlService.SandboxMode.IFRAME);

  return html;
}

function getReportListBy(cond) {
  cond.type = "viewingRecord";
  Logger.log(cond);

  var sheet = SpreadsheetApp.openById(ViewingRecordID).getSheetByName('鑑賞履歴');
  var lastRow = sheet.getLastRow();
  var results = sheet.getRange(3, 2, (lastRow - 2), 6).getValues();
  //Logger.log(results);

  return JSON.stringify(results);
}
```

#### Index.html
```haml
<!DOCTYPE html>
<html>
  <head>
  <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/themes/redmond/jquery-ui.css" />
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>

  <!-- Bootstrap -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/moment.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/locale/ja.js"></script>

  <?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?>
  <?!= HtmlService.createHtmlOutputFromFile('javascript').getContent(); ?>

  <script>
  var reportListCache = [];  // 検索結果退避
  </script>
    <base target="_top">
  </head>
  <body>
    <p></p>
    <div class="container-fluid">
    <table id="resultList" class="table table-striped table-bordered table-headerfixed">
      <thead class="scrollHead">
        <tr class="info">
          <th class="head01">ID</th>
          <th class="head01">鑑賞日</th>
          <th class="head02">タイトル</th>
          <th class="head01">初見</th>
          <th class="head01">鑑賞種別</th>
          <th class="head04">映画館</th>
        </tr>
      </thead>
      <tbody class="scrollBody"></tbody>
    </table>
    </div>
  </body>
</html>
```

#### javascript.html
```javascript
  <script>
  $(document).ready(function() {
    searchResults();
  });

  function searchResults() {
    var cond = {}; // 条件があれば...
    google.script.run.withSuccessHandler(
          function(v, element) {
            drawTable(v);
            reportListCache = v;
          })
        .withFailureHandler(
          function(msg, element) {
            showError(msg);
          })
        .withUserObject(this)
        .getReportListBy(cond);
  }

  function drawTable(data) {
    var records = JSON.parse(data)
    //console.log(records);
    var tag = '';
    for(var i = 0; i < records.length; i++) {
      tag += '<tr>';
      tag += '<td class="col01">'+ records[i][0] + '</td>';      
      tag += '<td class="col01">'+ convDate(records[i][1]) + '</td>';
      tag += '<td class="col02">'+ records[i][2] + '</td>';
      tag += '<td class="col01">'+ records[i][3] + '</td>';
      tag += '<td class="col01">'+ records[i][4] + '</td>';
      tag += '<td class="col04">'+ records[i][5] + '</td>';
      tag += '</tr>';
    }
    $('#resultList tbody').html(tag);
  }

  function convDate(date) {
    //console.log(date);
    var res = date.substr(5, 2) + '/' + date.substr(8, 2);
    return res;
  }

  function showError(msg) {
    console.log('msg:' + msg.toString());
    console.log(msg);
    alert(msg);
  }

  function convNaN(value) {
    var res = '';
    if(isFinite(value)) {
      res = value;
    }
    return res;
  }

  </script>
```

　こんな簡単なコードで、Webでの一覧表示が作れます。
　細かい説明は別に投稿していきますが、1ヶ所つまずいた所があるので記します。
　処理の大雑把な流れは次の様になっています。

1. **Index.html** が読み込まれて、**javascript.html** の`$(document).ready()`が実行されます。
1. 続けて、`searchResults()`が呼ばれます。
1. `searchResults()`では、サーバ側の処理（**ViewingRecord.gs**）`getReportListBy()`が呼び出されます。
1. `getReportListBy()`では、スプレッドシートのデータを取得して`return`に返し、その値を`searchResults()`の`google.script.run.withSuccessHandler()`で`v`として受け取る事ができます。

　最初、スプレッドシートのデータ（`results`）を直接`return`に渡していたのですが、この方法では値は渡りません。
　スプレッドシートのデータの様な配列のデータを渡す場合は、` JSON.stringify()`を使う（JSONデータにして渡す）必要があるそうです。
　なので、受ける側では`JSON.parse()`も使う（**javascript.html** の`drawTable()`）必要があります。
　**◆参考サイト** [Google Apps Scriptでウェブアプリケーション作成入門](https://officeforest.org/wp/2018/11/29/google-apps-script%E3%81%A7%E3%82%A6%E3%82%A7%E3%83%96%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E4%BD%9C%E6%88%90%E5%85%A5%E9%96%80/)

**◆次の記事** [GASでWebアプリ｢映画鑑賞記録｣を作る②](https://qiita.com/pump33/items/47633051e865ada707a2)

**◆索引** [GASでWebアプリ｢映画鑑賞記録｣を作る《索引》](https://qiita.com/pump33/items/8ded0e6fd3c336e705f4)