Google Apps ScriptでWebアプリケーション作成 その5

前回の続きです。index.htmlとコード.gsの2つのファイルを作り直しました。

Google Apps Scriptで作成するWebアプリケーションの初期表示のときに値をセットするようにしました。

Printing scriptlets 出力スクリプトレット

contextual escaping(コンテキストエスケープ)を使用してコードの結果がページに出力されます。

index.html

<h2><?=new Date()?></h2>

スクリプトレットは、Apps Scriptのコードファイルまたはライブラリで定義された関数を呼び出すことができます。new Date()。

また、Apps Scriptコードは、スクリプトレットで直接使用することもできます。

以下は、getOptionという作成した関数を呼び出しています。

index.html

          <?
          let res = getOptions();
          let keys = Object.keys(res)
          for (var i = 0; i < keys.length; i++) {
          ?>
              <option value="<?=keys[i]?>"><?=res[keys[i]]?></option>
          <?
          }
            ?>

コード.gs

/**
 * select の optionを取得
 */
function getOptions(){
  // スプレッドシートからもってくる処理 省略
  let options = {
    1: '111111',
    2: '222222',
    3: '333333'
  };
  console.log(Object.keys(options));
  return options;
}

Force-printing scriptlets 強制出力スクリプトレット

別の書き方でhtmlのタグの文字列を取得する関数を作成しました。getHtmlOptions()

htmlのタグを返すため、エスケープしてほしくありません。!マークを付けることで、そのままの値を出力できます。

index.html

<?!=getHtmlOptions()?>

変数をテンプレートにプッシュ

また、HtmlTemplateオブジェクトのプロパティとして変数を割り当てることで、変数をテンプレートにプッシュできます。

index.html

loginUserやkyouの変数です。

<p class="navbar-brand">ログインユーザー:<?= loginUser ?></p>
<input type="text" class="form-control datepicker" id="datepicker2" name="datepicker2" value="<?= kyou ?>">

コード.gs

コード.gsのなかでpushできます。

  template.kyou = Utilities.formatDate(new Date(), 'JST', 'yyyy/MM');
  template.loginUser = userEmail;

実行URL

https://script.google.com/macros/s/AKfycbwiTtWYutDbm05PyN72DUgSAbru07eaNW7kzlCQ2G6cqxPzzO9m/exec

index.html (全部)

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <base target="_top">
    <title>Jumbotron Template for Bootstrap</title>
 
    <!-- Bootstrap -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
     <!-- Bootstrap Datepicker -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css">
  </head>
  <body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="#">Project name</a>
          <p class="navbar-brand">ログインユーザー:<?= loginUser ?></p>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
        </div><!--/.navbar-collapse -->
      </div>
    </nav>
  
    <!-- Main jumbotron for a primary marketing message or call to action -->
    <div class="jumbotron">
      <div class="container">
        <h1>Hello, world!</h1>
        <!--Printing scriptlets 出力スクリプトレットタグ-->
        <h2><?=new Date()?></h2>
        <p>Bootstrap 3.4.1</p>
        <p>Bootstrap Datepicker 1.9.0</p>
        <p>jQuery 3.4.1</p>

        <form name="form2" id="form2" class="form-inline">
          <div class="form-group">
            <label for="datepicker2">年月 </label>
            <input type="text" class="form-control datepicker" id="datepicker2" name="datepicker2" value="<?= kyou ?>">
          </div>
          
          <div class="form-group">
            <label for="search_key_p">選択 </label>
            <select name="search_key_p" id="search_key_p" class="form-control">
          <?
          let res = getOptions();
          let keys = Object.keys(res)
          for (var i = 0; i < keys.length; i++) {
          ?>
              <option value="<?=keys[i]?>"><?=res[keys[i]]?></option>
          <?
          }
            ?>  
            </select>
            
            <label for="search_key_p">選択 </label>
            <select name="search_key_p" id="search_key_p" class="form-control">
          <?!=getHtmlOptions()?> 
            </select>  
            
          </div>
          
          <button type="button" class="btn btn-success" onclick="search();"><span class="glyphicon glyphicon-search"> 検索する</span></button>
        </form>
      </div>
    </div>

    <div class="container">
        <div class="col-md-12">
          <h2>Heading</h2>
          <p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
          <p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p>
        </div>

      <hr>

      <footer>
        <p>&copy; 2020 Company, Inc.</p>
      </footer>
    </div> <!-- /container -->
 
    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
    
    <!-- Bootstrap Datepicker -->
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/locales/bootstrap-datepicker.ja.min.js"></script>
   
 
    <script>
    $(function(){
      $('#datepicker2').datepicker({
        format: "yyyy/mm",
        language: "ja",
        autoclose: true,
        minViewMode: 'months'
      });
    });
    
    </script>
  </body>
</html>

コード.gs(全部)

const LOG_SHEET_ID = "1f9QNeD9MXzGJElZnvo6mmXFB4vW1qy1_T-tM58iKI9A"
 
function doGet(e)
{
  console.log(e);
  
  // getEmail()、getUserLoginId()はスクリプト実行者とスクリプトオーナーのドメインが同じ場合のみ動作する
  // 別ドメインのときはセキュリティ上、取得できない
  const userEmail = Session.getActiveUser().getEmail();
  
  // IDを指定してスプレッドシートを取得
  const logSheet = SpreadsheetApp.openById(LOG_SHEET_ID); 
  
  // シート名「log」に書き込む
  logSheet.getSheetByName('log').appendRow([new Date(), userEmail, 'doGet(e)', e]); 
  
  //index.htmlファイルからHtmlTemplateオブジェクトを生成
  const template = HtmlService.createTemplateFromFile('index');
  
  template.kyou = Utilities.formatDate(new Date(), 'JST', 'yyyy/MM');
  template.loginUser = userEmail;
  
  // evaluateメソッドでHtmlOutputオブジェクトを生成
  return template.evaluate().setTitle('Gas2');
}

/**
 * select の optionを取得
 */
function getOptions(){
  // スプレッドシートからもってくる処理 省略
  let options = {
    1: '111111',
    2: '222222',
    3: '333333'
  };
  console.log(Object.keys(options));
  return options;
}

/**
 * select の optionのhtmlタグを取得
 */
function getHtmlOptions(){
  // スプレッドシートからもってくる処理 省略
  let options = {
    1: '111111',
    2: '222222',
    3: '333333'
  };
  console.log(Object.keys(options));
  let keys = Object.keys(options)
  let htmlOptions
  for (let i = 0; i < keys.length; i++) {
    let str = "<option value=" + keys[i] + ">" + options[keys[i]] + "</option>"
    htmlOptions+=str
  }
  
  console.log(htmlOptions);
  return htmlOptions;
}

クライアントのフォームをGASに送信するには

index.htmlのformをsubmitするようにすれば、postまたはgetでコード.gsを実行することが可能になります。画面全体もリフレッシュされます。

今回は省略!

非同期でGASを呼び出すには

google.script.runを使えば、クライアントのJavaScriptからサーバー(GAS)の関数を呼び出すことができます。この場合、非同期の処理で実行できます。

ページ全体をgetまたはpostするのではなく、一部を書き換える非同期通信の処理のほうが転送量も少なく、ページ全体を書き換える必要もないためレスポンスもいいです。

GASでスプレッドシートの値の読み書きをする場合、かなり時間がかかりるため、Google Apps ScriptのWebアプリケーションは非同期処理がおすすめです。コードもシンプルになります。

非同期通信は次回!

cssとjsはインポートしたほうがいいのかな??あとで検討する。
↓参考ページ