PR

【GASの小技】テンプレートHTMLでラクラクWebアプリ化!HtmlService.createTemplateFromFile()の基本と使い方


こんにちは、イカPOです。
今回は HtmlService.createTemplateFromFile を使うと、テンプレートファイルを使用して HTML をブラウザに表示できます。

テンプレートファイルを作成するとコードの管理が楽になります。GAS で HTML を表示させるなら、前回紹介した HtmlService.createHtmlOutput() よりもおススメです。


HtmlService.createTemplateFromFile()の最小構成

ここでは「とにかく 1 画面出すだけ」の最短サンプルを示します。テンプレ分離のイメージをつかんでください。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <base target="_top">
</head>
<body>
  <h1>WEBアプリだよ</h1>
</body>
</html>
  • <base target="_top"> … 外部リンクを「親タブ」で開くためのおまじない。必須ではありませんが、Apps Script では入れておくのが通例です。

コード.gs

function doGet(e) {
  const template = HtmlService.createTemplateFromFile('index');
  const htmlOutput = template.evaluate();
  return htmlOutput;
}
処理内容
createTemplateFromFile('index')index.html を読み込みテンプレートオブジェクトを生成
evaluate()テンプレートを HtmlOutput に変換
return htmlOutputブラウザへ返却(doGet / doPost は必ず HtmlOutput を返す)

手順①:テンプレート HTML を作成する

HTML ファイル(ここでは index.html)をプロジェクト内に用意します。

メニューの+ボタンを押し、HTMLファイルを作成

その際に

<base target="_top">

を入れておくと、テンプレート内リンクが iframe ではなく親ウィンドウで開くようになります。“GAS で HTML を表示するときのお作法” と覚えておくとラクです。


手順②:doGet / doPost でテンプレートを読み込む

doGet(e) 内で、先ほど作ったテンプレートファイルを読み込みます。

const template = HtmlService.createTemplateFromFile('index');

HtmlService.createTemplateFromFile('ファイル名') で使用できます。今回作成したファイル名は「index」なので ('index') と書きます。

const htmlOutput = template.evaluate();

読み込んだ HTML ファイルを HtmlOutput オブジェクト に変換します。doGet() / doPost() では 文字列 ではなく このオブジェクトを return する のが約束事です。

return htmlOutput;

変換したオブジェクトを表示します。

まとめ
“ファイルを読み込む → テンプレートを展開する → return でブラウザに返す”
これが createTemplateFromFile の基本フローです。


生出力タグで GAS 生成のテーブル HTML をそのまま描画する

<?!= … ?> をテンプレート内で使用すると、GAS で作った HTML 要素をそのまま出力できます。以下に実例を載せます。


使用例

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <base target="_top">

  <title>WEBアプリだよ</title>

  <style>
    body { padding: 1rem; }
  </style>
</head>
<body>

  <h1>WEBアプリだよ</h1>
  <p>以下のように &lt;table&gt; タグで作成できます。</p>

  <div>
    <?!= itemTable ?>
  </div>

</body>
</html>
  • <?!= itemTable ?>エスケープせずに生 HTML をそのまま挿入します。

コード.gs

function doGet(e) {
  const template = HtmlService.createTemplateFromFile('table');
  template.itemTable = getItem();        // ← getItem() が返すテーブル HTML を渡す
  const htmlOutput = template.evaluate();
  return htmlOutput;
}

getItem() ― スプレッドシート → HTML テーブル変換

/**
 * 商品一覧シートからデータを取得し、HTML テーブル文字列を返す
 */
function getItem() {
  // ① アクティブなスプレッドシートを取得
  const ss = SpreadsheetApp.getActiveSpreadsheet();

  // ② 「商品一覧」シートを取得
  const sheet = ss.getSheetByName('商品一覧');
 
  // ③ シート全体の値を 2 次元配列で取得
  //    data[0] がヘッダー行、data[1] 以降がデータ行
  const data = sheet.getDataRange().getValues();

  // ④ 先頭行(ヘッダー)を取り出し、残りをデータとして保持
  const headers = data.shift();   // headers = ["商品ID", "商品名", "カテゴリー", "在庫数"]

  // ⑤ ヘッダー名 → 列インデックス の対応表を生成
  //    例: headerMap["商品名"] === 1
  const headerMap = {};
  headers.forEach(function(header, index) {
    headerMap[header] = index;
  });

  // ⑥ <thead> 部分 ─ ヘッダー配列を <th> で包み、空文字区切りで連結
  const thRow = headers
    .map(function(head) { return `<th>${head}</th>`; })
    .join('');

  // ⑦ <tbody> 部分 ─ 各データ行を <tr><td>…</td></tr> 形式の文字列に変換
  const tdRow = data
    .map(function(itemData) {
      return `
      <tr>
        <td>${parseInt(itemData[headerMap["商品ID"]], 10) || 0}</td>
        <td>${itemData[headerMap["商品名"]]}</td>
        <td>${itemData[headerMap["カテゴリー"]]}</td>
        <td>${parseInt(itemData[headerMap["在庫数"]], 10) || 0}</td>
      </tr>`;
    })
    .join('');

  // ⑧ 最終的な HTML テーブルを組み立て
  const html = `
    <table id="itemTable" class="table table-striped table-hover align-middle">
      <thead class="table-primary">
        <tr>${thRow}</tr>
      </thead>
      <tbody>${tdRow}</tbody>
    </table>`;

  // ⑨ 呼び出し元へ HTML 文字列を返す
  return html;
}

ポイント

  • ⑥で <thead>、⑦で <tbody> を個別に組み立てると、後でスタイルを付けやすくなります。
  • 数値列には parseInt() をかませておくと “空セル → 0” のフォールバックが効きます。

まず、前回も使用した 商品一覧シート → HTML テーブル文字列 を返す getItem() でテーブルを作成します。

template.itemTable = getItem();

その後、doGet 内で itemTable を定義し、テーブルの HTML 要素をテンプレートに渡します。

index.html 内の

<div>
  <?!= itemTable ?>
</div>

itemTable を呼び出しています。


HtmlService.createHtmlOutput() と HtmlService.createTemplateFromFile() のちがいについて

比較項目createHtmlOutput()createTemplateFromFile()
目的例すぐに “Hello world” を出したいHTML/CSS/JS を分割管理したい
HTML の書き方JS 文字列で直接書く外部 .html をテンプレートとして読み込む
変数の埋め込みreplace() 等で手動置換<?= var ?> / <?!= var ?> でワンタッチ
保守性長い HTML だと可読性↓ファイル分離で可読性◎

用途まとめ

  • createHtmlOutput() … デバッグ用、ワンライナーで済ませたいとき
  • createTemplateFromFile() … 本番 UI、複数ページ、リッチ画面を作るとき

createHtmlOutput()についての記事はこちらも


スタイル & JavaScript の組み込み

以下は Bootstrap + カスタム CSS + JavaScript の例
コードは原文そのまま掲載し、誤記タグのみ訂正しています。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <base target="_top">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <!-- Bootstrap 5 -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">


  <title>WEBアプリだよ</title>

  <style>
    body { padding: 1rem; }
    /* ───────────  テーブル全体  ─────────── */
    #itemTable {
      --bs-table-striped-bg: #f6faff;   /* 奇数行色 */
      --bs-table-hover-bg:   #edf4ff;   /* ホバー色 */
      border-radius: .5rem;
      overflow: hidden;
      box-shadow: 0 .125rem .75rem rgba(0,0,0,.05);
    }
    /* ───────────  ヘッダー  ─────────── */
    #itemTable thead th {
      background: #0d6efd;
      color: #fff;
      font-weight: 600;
      position: sticky; top: 0; z-index: 2;
    }
    /* ───────────  セルの配置調整  ─────────── */
    #itemTable tbody td:nth-child(1){text-align:center;}
    #itemTable tbody td:nth-child(4){text-align:right;}
    /* ───────────  カテゴリーをバッジ風  ─────────── */
    #itemTable tbody td:nth-child(3){
      font-weight: 500; padding:.35rem .75rem; border-radius:9999px;
      background:#e8f1ff; color:#0d6efd;
    }
  </style>
</head>
<body>

  <h1 class="h4 mb-3">WEBアプリだよ</h1>
  <p class="mb-4">以下のように &lt;table&gt; タグで作成できます。</p>

  <div class="table-responsive">
    <?!= itemTable ?>   <!-- テーブルを挿入 -->
  </div>

  <div class="d-flex gap-2 mt-4">
    <button id="addRowBtn" class="btn btn-primary btn-sm">行を追加</button>
  </div>

  <script>
    // デモ用:ダミーデータで行を追加
    document.getElementById('addRowBtn').addEventListener('click', () => {
      const tbody = document.querySelector('#itemTable tbody');
      const newRow = tbody.insertRow();
      const idCell = newRow.insertCell();
      const nameCell = newRow.insertCell();
      const categoryCell = newRow.insertCell();
      const stockCell = newRow.insertCell();

      const nextId = 1000 + tbody.rows.length;
      idCell.textContent = nextId;
      nameCell.textContent = 'デモ用品';
      categoryCell.textContent = 'テスト';
      stockCell.textContent = Math.floor(Math.random() * 10) + 1;
    });
  </script>
</body>
</html>

テンプレートファイル内に CSS と JavaScript を自由に書けるので、Bootstrap も組み合わせれば簡単にリッチな Web ページが作れます。外部ファイルにまとめて読み込む方法もありますが、それはまた別の記事で!


まとめ

  1. テンプレートファイルを分離すると、HTML/CSS/JS と GAS ロジックをきれいに分けられる。
  2. createTemplateFromFile()evaluate()return の 3 ステップが基本形。
  3. <?!= … ?> タグで GAS から渡した生 HTML をそのまま描画できる。
  4. Bootstrap などの外部ライブラリも普通の HTML と同じ要領で利用可能。

タイトルとURLをコピーしました