HTML-Dienst: Vorlagen-HTML

Sie können Apps Script-Code und HTML kombinieren, um mit minimalem Aufwand dynamische Seiten zu erstellen. Wenn Sie schon einmal eine Vorlagensprache verwendet haben, in der Code und HTML kombiniert werden, z. B. PHP, ASP oder JSP, sollte Ihnen die Syntax vertraut sein.

Scriptlets

Apps Script-Vorlagen können drei spezielle Tags enthalten, die Scriptlets. In einem Scriptlet können Sie beliebigen Code schreiben, der auch in einer normalen Apps Script-Datei funktionieren würde: Scriptlets können Funktionen aufrufen, die in anderen Codedateien definiert sind, auf globale Variablen verweisen oder eine der Apps Script APIs verwenden. Sie können sogar Funktionen und Variablen in Scriptlets definieren, mit der Einschränkung, dass sie nicht von Funktionen aufgerufen werden können, die in Codedateien oder anderen Vorlagen definiert sind.

Wenn Sie das Beispiel unten in den Script-Editor einfügen, wird der Inhalt des <?= ... ?>-Tags (ein Druck-Scriptlet) in Kursivschrift angezeigt. Dieser in Kursivschrift geschriebene Code wird auf dem Server ausgeführt, bevor die Seite an den Nutzer gesendet wird. Da Scriptlet-Code vor der Auslieferung der Seite ausgeführt wird, kann er nur einmal pro Seite ausgeführt werden. Im Gegensatz zu clientseitigen JavaScript- oder Apps Script-Funktionen, die über google.script.run aufgerufen werden, 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 Funktion doGet() für HTML-Vorlagen unterscheidet sich von den Beispielen zum Erstellen und Bereitstellen einfacher HTML-Inhalte. 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 umzuwandeln, das dem Nutzer vom Script bereitgestellt werden kann.

Standard-Scriptlets

Standard-Scriptlets mit der Syntax <? ... ?> führen Code aus, ohne Inhalte explizit auf der Seite auszugeben. Wie dieses Beispiel zeigt, kann sich das Ergebnis des Codes in einem Scriptlet jedoch auf den HTML-Inhalt außerhalb des Scriptlets auswirken:

Code.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

Index.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <? if (true) { ?>
      <p>This will always be served!</p>
    <? } else  { ?>
      <p>This will never be served.</p>
    <? } ?>
  </body>
</html>

Scriptlets drucken

Druck-Scriptlets, die die Syntax <?= ... ?> verwenden, geben die Ergebnisse ihres Codes mithilfe von kontextbezogenem Escape-Code auf der Seite aus.

Bei kontextbezogenem Entkommenttieren wird in Apps Script der Kontext der Ausgabe auf der Seite überwacht – innerhalb eines HTML-Attributs, eines clientseitigen script-Tags oder an anderer Stelle – und es werden automatisch Escape-Zeichen hinzugefügt, um vor Cross-Site-Scripting-Angriffen (XSS) zu schützen.

In diesem Beispiel gibt das erste Druckscriptlet einen String direkt aus. Es wird gefolgt von einem Standardscriptlet, das ein Array und eine Schleife einrichtet, und einem weiteren Druckscriptlet, 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>

Hinweis: Ein Druckscriptlet gibt nur den Wert seiner ersten Anweisung aus. Alle verbleibenden Anweisungen verhalten sich so, als wären sie in einem Standardscriptlet enthalten. So gibt das Scriptlet <?= 'Hello, world!'; 'abc' ?> beispielsweise nur „Hallo Welt!“ aus.

Scriptlets für erzwungenes Drucken

Scriptlets für den Erzwingen des Druckens, die die Syntax <?!= ... ?> verwenden, ähneln Druckscriptlets, mit der Ausnahme, dass sie das kontextbezogene Entkommen vermeiden.

Kontextbezogenes Entkommenttieren ist wichtig, wenn Ihr Script nicht vertrauenswürdige Nutzereingaben zulässt. Im Gegensatz dazu müssen Sie den Druck erzwingen, wenn die Ausgabe Ihres Scriptlets absichtlich HTML oder Scripts enthält, die genau wie angegeben eingefügt werden sollen.

Verwenden Sie in der Regel Druck-Scriptlets anstelle von Erzwingungs-Druck-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 das Ausführen von normalem JavaScript beschränkt. Sie können auch eine der folgenden drei Methoden verwenden, um Ihren Vorlagen Zugriff auf Apps Script-Daten zu gewähren.

Da der Vorlagencode jedoch ausgeführt wird, bevor die Seite für den Nutzer angezeigt wird, können mit diesen Techniken nur anfängliche Inhalte auf einer Seite bereitgestellt werden. Wenn Sie interaktiv auf Apps Script-Daten auf einer Seite zugreifen möchten, verwenden Sie stattdessen die google.script.run API.

Apps Script-Funktionen über eine Vorlage aufrufen

Scriptlets können jede Funktion aufrufen, die in einer Apps Script-Codedatei oder -Bibliothek definiert ist. In diesem Beispiel wird eine Möglichkeit gezeigt, Daten aus einer Tabelle in eine Vorlage einzufügen und dann eine HTML-Tabelle aus den Daten zu 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 das gleiche Ergebnis wie im vorherigen Beispiel erzielt, indem die Daten in der Vorlage selbst und nicht über eine separate Funktion geladen werden.

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 einfügen

Schließlich können Sie Variablen in eine Vorlage einfügen, indem Sie sie als Eigenschaften des Objekts HtmlTemplate 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 für die Fehlerbehebung

Das Entfernen von Fehlern in Vorlagen kann schwierig sein, da der von Ihnen geschriebene Code nicht direkt ausgeführt wird. Stattdessen wandelt der Server die Vorlage in Code um und führt diesen dann aus.

Wenn Sie nicht sicher sind, wie die Vorlage Ihre Scriptlets interpretiert, können zwei Debugging-Methoden in der Klasse HtmlTemplate Ihnen dabei helfen, das Problem besser zu verstehen.

getCode()

getCode() gibt einen String zurück, der den Code enthält, den der Server aus der Vorlage erstellt. Wenn Sie den Code protokollieren und dann in den Script-Editor einfügen, können Sie ihn wie normalen Apps Script-Code ausführen und debuggen.

Hier ist die einfache Vorlage, in der wieder eine Liste von Google-Produkten 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 (BEWERTET)

(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('');
})();

getCodeWithComments()

getCodeWithComments()ähnelt getCode(), gibt den ausgewerteten Code aber als Kommentare zurück, die neben der ursprünglichen Vorlage angezeigt werden.

Ausgewerteten Code durchgehen

In beiden Beispielen für ausgewerteten Code fällt als Erstes das implizite output-Objekt auf, 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 _$. Sie sind eine Kurzform für append() und appendUntrusted().

output hat noch eine weitere spezielle Property, $out, die sich auf ein reguläres HtmlOutput-Objekt bezieht, das diese speziellen Properties nicht hat. Die Vorlage gibt dieses normale Objekt am Ende des Codes zurück.

Nachdem Sie diese Syntax verstanden haben, sollte der Rest des Codes ziemlich einfach zu verstehen sein. HTML-Inhalte außerhalb von Scriptlets (z. B. das b-Tag) werden mit output._ = (ohne kontextbezogenes Entkommentieren) angehängt und Scriptlets werden als JavaScript angehängt (je nach Scriptlettyp mit oder ohne kontextbezogenes Entkommentieren).

Beachten Sie, dass die Zeilennummern aus der Vorlage im ausgewerteten Code beibehalten werden. 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 die 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 will print 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. */ ?>