質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

2353閲覧

GASのサイトで表を定期的に更新できない

aiueomaruta

総合スコア27

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

2クリップ

投稿2021/09/25 05:04

編集2021/09/25 05:11

google apps scriptでチャットを作っているのですが、チャットを定期的に更新するプログラムを作るところで詰まっています。

チャットはスプレッドシートにコメントを追加していくものです。

スプレッドシートの下から20個を定期的に更新しながら表示するプログラムを作っています。

コード.gs

js

1function doGet(){ 2 var html = HtmlService.createTemplateFromFile("index"); 3 return html.evaluate(); 4} 5 6function send(text){ 7 var user = Session.getActiveUser(); 8 SpreadsheetApp.openById("スプレッドシートid").appendRow([user,text]) 9} 10 11function load(){ 12 var values = SpreadsheetApp.openById("スプレッドシートid").getDataRange().getValues(); 13 output.append('<table border="1" style="table-layout: fixed;">'); 14 for(var i=values.length-20;i<values.length;i++){ 15 output.append('<tr>'); 16 output.append('<th><font bgcolor=blue color="#000000">'+values[i][0]+'</th>'); 17 output.append('<th><font bgcolor=blue color="#000000">'+values[i][1]+'</th>'); 18 output.append('</tr>'); 19 } 20 output.append('</table>'); 21}

index.html

html

1<!DOCTYPE html> 2<html> 3 <head> 4 <base target="_top"> 5 </head> 6 <body> 7 チャット 8 <input type="text" id="text"> 9 <button id="button">送信</button> 10 <br> 11 <script> 12 setInterval(<?=load()?>, 3000); 13 document.getElementById("button").onclick=sendm; 14 function sendm(){ 15 var text = document.getElementById("text").value; 16 document.getElementById("text").value=""; 17 google.script.run.send(text); 18 } 19 </script> 20 </body> 21</html>

このプログラムだと、
ReferenceError: 「output」が定義されていません。
というエラーが出ています。

僕はこれまで、htmlの方に<??>output.append()を使って表を作っていてうまくいっていたのですが、setInterval()が一緒に使えそうになかったのでJavaScriptの方に移しました。

エラーが直ったとしても、コメントの欄が何重にも出てきてしまうのはわかっています。

エラーを修正する方法、または<??>の中のものをsetInterval()で呼び出す方法、など、教えてください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/09/25 09:40 編集

テンプレートとスクリプトレットを用いてチャットの最新20件を取得し、3秒ごとに更新して表示しようとされているようですが、更新表示の際にページを更新(F5キーと同じ動作)することが前提という理解でよろしいでしょうか。
aiueomaruta

2021/09/25 09:40

ページは更新しません。開いたらそのまま永続的にチャットを更新し続けるものを作ろうとしています。
guest

回答1

0

ベストアンサー

このプログラムだと、ReferenceError: 「output」が定義されていません。というエラーが出ています。

「output」というのは、HtmlService.initTemplate() というメソッドにより生成される暗黙オブジェクトです。
Google Apps Script の暗黙オブジェクト

なので、質問文のようにHtmlServiceと関係ない場所(.gsファイルの無関係な関数内)でoutputを使おうとしても「定義されていません」というエラーになってしまいます。
(outputは、テンプレートhtmlファイルのスクリプトレット内で使用することが多いです。createFromHtmlTemplateFile()関数を呼び出す段階でHtmlService.initTemplate()が呼ばれるためoutputが使用可能になります)

そして、テンプレートファイルは、evaluate()の実行時に、スクリプトレット(<? ~~ ?>等の記号で囲まれた部分)が展開され、完全なHTMLページとなりますが
ページが読み込まれた後にスクリプトレットを再実行することは、基本的にできないことに注意する必要があります。

Because scriptlet code executes before the page is served, it can only run once per page; unlike client-side JavaScript or Apps Script functions that you call through google.script.run, scriptlets can't execute again after the page loads.

(スクリプトレットのコードは、ページが提供される前に実行されるため、1ページにつき1回しか実行できません。クライアントサイドのJavaScriptやApps Scriptの関数をgoogle.script.runで呼び出す場合とは異なり、ページが読み込まれた後にスクリプトレットを再実行することはできません。)

(ドキュメントより引用)


以上より、ページ更新(F5キーと同じ動作)を行わず、ページを開いたままチャットデータを更新しようとするような場合、更新データそのものをスクリプトレットを含んだテンプレートにしてしまうと、少々難易度が高くなる気がします。
(方法として、内部フレームにチャットデータを閉じ込めてフレーム部分を部分更新するとかでしょうか・・・)
(※なお、今回の目的のためにcreateFromHtmlTemplateFileが全く使えないというわけではありません。ページの静的な組み立て(初期データの表示)にも使える余地はあります)


ではページ更新を使わず、データを更新するにはどうするかですが、テーブルのDOMを更新するやり方があります。

下記が全体プログラムになります。デプロイ時は、「アクセスできるユーザー」を「全員」に設定してください。
code.gs

js

1// getActive()を使うと権限エラーとなるため、openById又はopenByUrlを使うこと。 2var sheet = SpreadsheetApp.openById("~~").getSheetByName("シート1"); 3 4function doGet(){ 5 var html = HtmlService.createHtmlOutputFromFile("index"); 6 return html; 7} 8 9 10function getData(){ 11 return sheet.getDataRange().getValues() 12} 13 14function send(text){ 15 var user = Session.getActiveUser(); 16 sheet.appendRow([user,text]); 17}

index.html

HTML

1<!DOCTYPE html> 2<html> 3 <head> 4 <base target="_top"> 5 </head> 6 <body> 7 チャット 8 <input type="text" id="text"> 9 <button id="button">送信</button> 10 <br> 11 12 <table id="chat-table" border="1" style="table-layout: fixed;"> 13 <tr> 14 <th>USER</th> 15 <th>CHAT</th> 16 </tr> 17 </table> 18 19 <script> 20 // 書き込んだデータの最終インデックス 21 var lastrow = 0; 22 23 //最初の読み込み時に実行 24 window.addEventListener('DOMContentLoaded', function(){ 25 document.getElementById("button").onclick=sendm; 26 // 一番最初はすぐにデータを読み込む 27 load(); 28 setInterval(load, 3000); 29 }); 30 31 // チャットデータをコード.gsから取得。 32 function load(){ 33 google.script.run 34 .withSuccessHandler(appendTableRows).getData(); 35 } 36 37 function appendTableRows(values){ 38 if(values == null|| values[0]=='') return; 39 40 var table = document.getElementById("chat-table"); 41 42 for(var i = lastrow; i < values.length; i++){ 43 var row = table.insertRow(-1); 44 row.insertCell(0).innerHTML = '<td><font bgcolor=blue color="#000000">'+values[i][0]+'</td>'; 45 row.insertCell(1).innerHTML = '<td><font bgcolor=blue color="#000000">'+values[i][1]+'</td>'; 46 } 47 // 書き込んだデータの最終インデックスを更新する。 48 lastrow = values.length 49 } 50 51 function sendm(){ 52 var text = document.getElementById("text").value; 53 document.getElementById("text").value=""; 54 google.script.run.send(text); 55 } 56 57 </script> 58 </body> 59</html>

チャットデータの更新は、下記のようにして行っています。

・load 関数内で、withSuccessHandlerを使って非同期にコード.gsのgetData関数を呼び出し、
getData関数から取得したチャットデータを、appendTableRows に渡す。
・appendTableRows 内で、tableのDOMを更新してテーブルの行を追加する。

js

1 function load(){ 2 google.script.run 3 .withSuccessHandler(appendTableRows).getData(); 4 }

js

1 function appendTableRows(values){ 2 if(values == null || values[0]=='') return; 3 4 var table = document.getElementById("chat-table"); 5 6 for(var i = lastrow; i < values.length; i++){ 7 var row = table.insertRow(-1); 8 row.insertCell(0).innerHTML = '<td><font bgcolor=blue color="#000000">'+values[i][0]+'</td>'; 9 row.insertCell(1).innerHTML = '<td><font bgcolor=blue color="#000000">'+values[i][1]+'</td>'; 10 } 11 // 書き込んだデータの最終インデックスを更新する。 12 lastrow = values.length 13 }

なお、同じチャットが重複して表示されないように、lastrow というグローバル変数に、書き込んだデータの最終インデックスを保持しておき、更新のあった分だけ追加するようにしています。


このスクリプトではまだ「20行だけに固定」というのは示していませんが、基本的に上記スクリプトを拡張することでできます。御自分で考えてみて下さい。
(この場合createFromHtmlTemplateFileを使うことになると思いますが)

上記は素案として作っただけで、まだまだブラッシュアップの余地はたくさんあります。

20行固定表示以外にも、最初のチャットデータ表示をもっと早くする方法を考えたり、チャットデータの転送量を減らす方法を考えたり(上記スクリプトだとチャットデータを全部送っている)、Vueで作り直したりするのも面白いと思います。

投稿2021/09/25 13:24

編集2021/09/30 11:59
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aiueomaruta

2021/09/25 13:53

回答ありがとうございます。まだ読み途中ですが、参考になります!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問