Mit Vorlagen können Sie Google Apps Script-Code und HTML mischen, um dynamische Seiten mit minimalem Aufwand zu erstellen. Wenn Sie bereits Vorlagensprachen verwendet haben, in denen Code und HTML gemischt werden, z. B. PHP, ASP oder JSP, sollte Ihnen die Syntax vertraut sein.
Scriptlets
Apps Script-Vorlagen können drei spezielle Tags enthalten, die als Scriptlets bezeichnet werden. In einem Scriptlet können Sie beliebigen Code schreiben, der in einer normalen Apps Script-Datei funktioniert: Scriptlets können Funktionen aufrufen, die in anderen Code-Dateien definiert sind, auf globale Variablen verweisen oder eine der Apps Script-APIs verwenden. Sie können sogar Funktionen und Variablen in Scriptlets definieren. Diese können jedoch nicht von Funktionen aufgerufen werden, die in Code-Dateien oder anderen Vorlagen definiert sind.
Wenn Sie das folgende Beispiel in den Script-Editor einfügen, wird der Inhalt des <?= ... ?>-Tags (ein Print-Scriptlet) kursiv dargestellt. Dieser Code wird auf dem Server ausgeführt, bevor die Seite dem Nutzer präsentiert wird. Da Scriptlet-Code vor der Bereitstellung der Seite ausgeführt wird, kann er nur einmal pro Seite ausgeführt werden. Im Gegensatz zu clientseitigen JavaScript- oder Apps Script-Funktionen, die Sie über google.script.run aufrufen, können Scriptlets nach dem Laden der Seite nicht noch einmal ausgeführt werden.
Code.gs
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Hello, World! The time is <?= new Date() ?>.
</body>
</html>
Die doGet-Funktion für HTML-Vorlagen unterscheidet sich von den Beispielen für das Erstellen und Bereitstellen von einfachem HTML. Die hier gezeigte Funktion generiert ein HtmlTemplate-Objekt aus der HTML-Datei und ruft dann die Methode evaluate auf, um die Scriptlets auszuführen und die Vorlage in ein HtmlOutput-Objekt zu konvertieren, das vom Script an den Nutzer gesendet werden kann.
Standard-Scriptlets
Standard-Scriptlets, die die Syntax <? ... ?> verwenden, führen Code aus, ohne explizit Inhalte auf der Seite auszugeben. Wie dieses Beispiel zeigt, kann das Ergebnis des Codes in einem Scriptlet jedoch weiterhin den HTML-Inhalt außerhalb des Scriptlets beeinflussen:
Code.gs
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<? if (true) { ?>
<p>This is always served!</p>
<? } else { ?>
<p>This is never served.</p>
<? } ?>
</body>
</html>
Scriptlets drucken
Bei Scriptlets, die die Syntax <?= ... ?> verwenden, werden die Ergebnisse des Codes mithilfe des kontextbezogenen Escapings auf der Seite ausgegeben.
Beim kontextbezogenen Escaping wird der Kontext der Ausgabe auf der Seite (in einem HTML-Attribut, in einem clientseitigen script-Tag oder an einer anderen Stelle) von Apps Script verfolgt und es werden automatisch Escapezeichen hinzugefügt, um vor Cross-Site-Scripting-Angriffen (XSS) zu schützen.
In diesem Beispiel gibt das erste Druck-Scriptlet einen String direkt aus. Es folgt ein Standard-Scriptlet, das ein Array und eine Schleife einrichtet, gefolgt von einem weiteren Druck-Scriptlet, das den Inhalt des Arrays ausgibt.
Code.gs
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<?= 'My favorite Google products:' ?>
<? var data = ['Gmail', 'Docs', 'Android'];
for (var i = 0; i < data.length; i++) { ?>
<b><?= data[i] ?></b>
<? } ?>
</body>
</html>
Ein Druck-Scriptlet gibt nur den Wert der ersten Anweisung aus. Alle verbleibenden Anweisungen verhalten sich so, als wären sie in einem Standard-Scriptlet enthalten. Das Scriptlet <?= 'Hello, world!'; 'abc' ?> gibt also nur „Hello, world!“ aus.
Scriptlets erzwingen
Scriptlets für den erzwungenen Druck, die die Syntax <?!= ... ?> verwenden, ähneln Druck-Scriptlets, vermeiden jedoch das kontextbezogene Escaping.
Kontextbezogenes Escaping ist wichtig, wenn Ihr Skript nicht vertrauenswürdige Nutzereingaben zulässt. Im Gegensatz dazu müssen Sie das Scriptlet-Ergebnis erzwingen, wenn es absichtlich HTML oder Scripts enthält, die Sie genau wie angegeben einfügen möchten.
Verwenden Sie in der Regel Druck-Scriptlets anstelle von Force-Print-Scriptlets, es sei denn, Sie wissen, dass Sie HTML oder JavaScript unverändert drucken müssen.
Apps Script-Code in Scriptlets
Scriptlets sind nicht auf die Ausführung von normalem JavaScript beschränkt. Sie können auch eine der folgenden drei Techniken verwenden, um Ihren Vorlagen Zugriff auf Apps Script-Daten zu gewähren.
Da Vorlagencode jedoch ausgeführt wird, bevor die Seite dem Nutzer präsentiert wird, können mit diesen Methoden nur erste Inhalte auf einer Seite bereitgestellt werden. Wenn Sie interaktiv von einer Seite aus auf Apps Script-Daten zugreifen möchten, verwenden Sie stattdessen die google.script.run API.
Apps Script-Funktionen über eine Vorlage aufrufen
In Scriptlets kann jede Funktion aufgerufen werden, die in einer Apps Script-Codedatei oder -Bibliothek definiert ist. In diesem Beispiel wird gezeigt, wie Sie Daten aus einem Tabellenblatt in eine Vorlage einfügen und dann eine HTML-Tabelle aus den Daten erstellen.
Code.gs
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
function getData() {
return SpreadsheetApp
.openById('1234567890abcdefghijklmnopqrstuvwxyz')
.getActiveSheet()
.getDataRange()
.getValues();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<? var data = getData(); ?>
<table>
<? for (var i = 0; i < data.length; i++) { ?>
<tr>
<? for (var j = 0; j < data[i].length; j++) { ?>
<td><?= data[i][j] ?></td>
<? } ?>
</tr>
<? } ?>
</table>
</body>
</html>
Apps Script-APIs direkt aufrufen
Sie können Apps Script-Code auch direkt in Scriptlets verwenden. In diesem Beispiel wird dasselbe Ergebnis wie im vorherigen Beispiel erzielt, indem die Daten in die Vorlage selbst geladen werden und nicht über eine separate Funktion.
Code.gs
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<? var data = SpreadsheetApp
.openById('1234567890abcdefghijklmnopqrstuvwxyz')
.getActiveSheet()
.getDataRange()
.getValues(); ?>
<table>
<? for (var i = 0; i < data.length; i++) { ?>
<tr>
<? for (var j = 0; j < data[i].length; j++) { ?>
<td><?= data[i][j] ?></td>
<? } ?>
</tr>
<? } ?>
</table>
</body>
</html>
Variablen in Vorlagen übertragen
Schließlich können Sie Variablen in eine Vorlage einfügen, indem Sie sie als Attribute des HtmlTemplate-Objekts zuweisen. Auch in diesem Beispiel wird dasselbe Ergebnis wie in den vorherigen Beispielen erzielt.
Code.gs
function doGet() {
var t = HtmlService.createTemplateFromFile('Index');
t.data = SpreadsheetApp
.openById('1234567890abcdefghijklmnopqrstuvwxyz')
.getActiveSheet()
.getDataRange()
.getValues();
return t.evaluate();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<table>
<? for (var i = 0; i < data.length; i++) { ?>
<tr>
<? for (var j = 0; j < data[i].length; j++) { ?>
<td><?= data[i][j] ?></td>
<? } ?>
</tr>
<? } ?>
</table>
</body>
</html>
Vorlagen debuggen
Vorlagen können schwierig zu debuggen sein, da der von Ihnen geschriebene Code nicht direkt ausgeführt wird. Stattdessen wird die Vorlage vom Server in Code umgewandelt und dieser Code dann ausgeführt.
Wenn nicht klar ist, wie das Template Ihre Scriptlets interpretiert, können Sie mit zwei Debugging-Methoden in der Klasse HtmlTemplate besser nachvollziehen, was passiert.
Die Funktion „getCode“
Die Funktion getCode gibt einen String mit dem Code zurück, den der Server aus der Vorlage erstellt.
Wenn Sie den Code protokollieren und dann in den Skripteditor einfügen, können Sie ihn wie normalen Apps Script-Code ausführen und debuggen.
Hier sehen Sie die Vorlage, in der noch einmal eine Liste der Google-Produkte und dann das Ergebnis von getCode angezeigt wird:
Code.gs
function myFunction() {
Logger.log(HtmlService
.createTemplateFromFile('Index')
.getCode());
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<?= 'My favorite Google products:' ?>
<? var data = ['Gmail', 'Docs', 'Android'];
for (var i = 0; i < data.length; i++) { ?>
<b><?= data[i] ?></b>
<? } ?>
</body>
</html>
LOG (EVALUATED)
(function() { var output = HtmlService.initTemplate(); output._ = '<!DOCTYPE html>\n';
output._ = '<html>\n' +
' <head>\n' +
' <base target=\"_top\">\n' +
' </head>\n' +
' <body>\n' +
' '; output._$ = 'My favorite Google products:' ;
output._ = ' '; var data = ['Gmail', 'Docs', 'Android'];
for (var i = 0; i < data.length; i++) { ;
output._ = ' <b>'; output._$ = data[i] ; output._ = '</b>\n';
output._ = ' '; } ;
output._ = ' </body>\n';
output._ = '</html>';
/* End of user code */
return output.$out.append('');
})();
Die Funktion „getCodeWithComments“
Die Funktion getCodeWithComments ähnelt getCode(), gibt den ausgewerteten Code jedoch als Kommentare zurück, die nebeneinander mit der ursprünglichen Vorlage angezeigt werden.
Bewerteten Code durchgehen
Das Erste, was Sie in beiden Beispielen für ausgewerteten Code bemerken werden, ist das implizite output-Objekt, das von der Methode HtmlService.initTemplate erstellt wird. Diese Methode ist nicht dokumentiert, da sie nur von Vorlagen selbst verwendet werden muss. output ist ein spezielles HtmlOutput-Objekt mit zwei ungewöhnlich benannten Properties, _ und _$, die eine Kurzform für den Aufruf von append und appendUntrusted sind.
output hat eine weitere spezielle Eigenschaft, $out, die sich auf ein reguläres HtmlOutput-Objekt bezieht, das diese speziellen Eigenschaften nicht besitzt. Die Vorlage gibt dieses normale Objekt am Ende des Codes zurück.
Nachdem Sie diese Syntax verstanden haben, können Sie den Rest des Codes nachvollziehen. HTML-Inhalte außerhalb von Scriptlets (z. B. das b-Tag) werden mit output._ = angehängt (ohne kontextbezogene Escapesequenzen). Scriptlets werden als JavaScript angehängt (mit oder ohne kontextbezogene Escapesequenzen, je nach Art des Scriptlets).
Im ausgewerteten Code werden die Zeilennummern aus der Vorlage beibehalten. Wenn beim Ausführen des ausgewerteten Codes ein Fehler auftritt, entspricht die Zeile dem entsprechenden Inhalt in der Vorlage.
Hierarchie der Kommentare
Da bei ausgewertetem Code Zeilennummern beibehalten werden, können Kommentare in Scriptlets andere Scriptlets und sogar HTML-Code auskommentieren. Diese Beispiele zeigen einige überraschende Auswirkungen von Kommentaren:
<? var x; // a comment ?> This sentence won't print because a comment begins
inside a scriptlet on the same line.
<? var y; // ?> <?= "This sentence won't print because a comment begins inside
a scriptlet on the same line.";
output.append("This sentence prints because it's on the next line, even though
it's in the same scriptlet.") ?>
<? doSomething(); /* ?>
This entire block is commented out,
even if you add a */ in the HTML
or in a <script> */ </script> tag,
<? until you end the comment inside a scriptlet. */ ?>