はじめに
「画面の共通部分を部品化して、複数の画面から使いたい」ということはよくあると思います。
これまで経験したプロジェクトでも include
という関数を作ってそのようなことを実現してきていましたが、インクルード先ではスクリプトレットが使えない、など制限があるものでした。
もっと使いやすくならないかといろいろ試した結果を書いておきます。
対象者
- 基本的な JavaScript が読める方
- GAS で Web アプリを作ったことがある方
いきなり結論
試行錯誤の結果、これでやりたかった以下のことができました。
- インクルード先の HTML でもスクリプトレットを使える
- インクルードのネスト(インクルード先でインクルード可能)
- インクルード先にパラメーターを渡せる
Code.gs
/**
* HTMLをインクルードする.
*
* @param {string} filename HTMLファイル名
* @param {Object} params インクルード先に渡すパラメーター
*/
function include(filename, params) {
const template = HtmlService.createTemplateFromFile(filename);
if (params) {
for (const key in params) {
template[key] = params[key];
}
}
return template.evaluate().getContent();
}
動作確認
の include
関数を動作確認します。
以下のように複数の HTML を作りました。
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('css'); ?>
</head>
<body class="index">
<h2>this is index.</h2>
<?!= include('sub1'); ?>
<?!= include('sub2', { a:1, b:2 }); ?>
</body>
</html>
css.html
<style>
div {
margin: 5px;
padding: 5px;
}
.index { background-color: #ffffff; } /* 白 */
.calc { background-color: #99ffff; } /* 水色 */
.sub1 { background-color: #99ff99; } /* 緑 */
.sub2 { background-color: #ffff99; } /* 黄色 */
.sub2_1 { background-color: #9999ff; } /* 紫 */
</style>
calc.html
<div class="calc">
<h4>this is calc.</h4>
<?= a ?> + <?= b ?> = <?= a + b ?>
</div>
sub1.html
<div class="sub1">
<h3>this is sub1.</h3>
<?
const a = 'A';
const b = 'B';
?>
<?= a + b ?>
</div>
sub2.html
<div class="sub2">
<h3>this is sub2.</h3>
<?!= include('calc', { a:a, b:b }); ?>
<?!= include('sub2_1', { a:a*2, b:b*2 }); ?>
</div>
sub2_1.html
<div class="sub2_1">
<h3>this is sub2_1.</h3>
<?!= include('calc', { a:a, b:b }); ?>
</div>
HTML どうしの関係は以下のようになっています。
- index.html
- css.html
- sub1.html
- sub2.html
- calc.html
- sub2_1.html
- calc.html
つづけて Code.gs
に doGet
を追加します。
Code.gs
function doGet(e) {
return HtmlService.createTemplateFromFile('index').evaluate();
}
最後に作成した Web アプリにアクセスすると以下のように表示され、期待通りの動作が確認できました。
所感
- GAS で HTML を扱うクラスには、
HtmlOutput
やHtmlTemplate
があり、色々と機能を持っているようなのでもっと深堀りしてみると面白そうです -
doGet
関数はHtmlOutput
を返す必要があるようなので、最初はreturn HtmlService.createHtmlOutputFromFile('index');
と書いていましたが、これではインクルードが期待通り動きませんでした。- 一度
HtmlTemplate
経由でHtmlOutput
を生成することに意味がある模様
- 一度