Vous pouvez utiliser des modèles pour combiner du code Google Apps Script et du code HTML afin de créer des pages dynamiques avec un minimum d'efforts. Si vous avez déjà utilisé des langages de modèle qui combinent du code et du code HTML, tels que PHP, ASP ou JSP, la syntaxe devrait vous être familière.
Scriptlets
Les modèles Apps Script peuvent contenir trois balises spéciales appelées scriptlets. Dans un scriptlet, vous pouvez écrire n'importe quel code qui fonctionne dans un fichier Apps Script normal : les scriptlets peuvent appeler des fonctions définies dans d'autres fichiers de code, référencer des variables globales ou utiliser n'importe quelle API Apps Script. Vous pouvez même définir des fonctions et des variables dans des scriptlets, à condition qu'elles ne puissent pas être appelées par des fonctions définies dans des fichiers de code ou d'autres modèles.
Si vous collez l'exemple suivant dans l'éditeur de script, le contenu de la
<?= ... ?> balise (un scriptlet d'impression) s'affiche en
italique. Ce code s'exécute sur le serveur avant que la page ne soit diffusée à l'utilisateur. Étant donné que le code du scriptlet s'exécute avant la diffusion de la page, il ne peut s'exécuter qu'une seule fois par page. Contrairement aux fonctions JavaScript côté client ou
Apps Script que vous appelez via
google.script.run, les scriptlets ne peuvent pas
s'exécuter à nouveau après le chargement de la page.
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>
Notez que la fonction doGet pour le code HTML basé sur un modèle diffère des exemples
pour créer et diffuser du code HTML de base. La fonction
présentée ici génère un
HtmlTemplate objet à partir du fichier HTML, puis appelle sa méthode
evaluate pour
exécuter les scriptlets et convertir le modèle en un objet
HtmlOutput que le script
peut diffuser à l'utilisateur.
Scriptlets standards
Les scriptlets standards, qui utilisent la syntaxe <? ... ?>, exécutent du code sans
générer explicitement de contenu sur la page. Toutefois, comme le montre cet exemple, le résultat du code dans un scriptlet peut toujours affecter le contenu HTML en dehors du scriptlet :
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 d'impression
Les scriptlets d'impression, qui utilisent la syntaxe <?= ... ?>, génèrent les résultats de
leur code dans la page à l'aide de l'échappement contextuel.
L'échappement contextuel signifie qu'Apps Script suit le contexte de la sortie sur la page (dans un attribut HTML, dans une balise côté client
script ou ailleurs) et ajoute automatiquement des caractères d'échappement pour
se protéger contre les attaques de script intersites (XSS).
Dans cet exemple, le premier scriptlet d'impression génère directement une chaîne. Il est suivi d'un scriptlet standard qui configure un tableau et une boucle, puis d'un autre scriptlet d'impression pour générer le contenu du tableau.
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>
Notez qu'un scriptlet d'impression ne génère que la valeur de sa première instruction. Toutes les instructions restantes se comportent comme si elles étaient contenues dans un scriptlet standard. Ainsi, par exemple, le scriptlet <?= 'Hello, world!'; 'abc' ?> n'imprime que "Hello, world!"
Scriptlets d'impression forcée
Les scriptlets d'impression forcée, qui utilisent la syntaxe <?!= ... ?>, sont semblables aux scriptlets d'impression
, sauf qu'ils évitent l'échappement contextuel.
L'échappement contextuel est important si votre script autorise la saisie de données utilisateur non fiables. En revanche, vous devrez forcer l'impression si la sortie de votre scriptlet contient intentionnellement du code HTML ou des scripts que vous souhaitez insérer exactement comme spécifié.
En règle générale, utilisez des scriptlets d'impression plutôt que des scriptlets d'impression forcée, sauf si vous savez que vous devez imprimer du code HTML ou JavaScript sans le modifier.
Code Apps Script dans les scriptlets
Les scriptlets ne sont pas limités à l'exécution de code JavaScript normal. Vous pouvez également utiliser l'une des trois techniques suivantes pour donner à vos modèles accès aux données Apps Script.
N'oubliez pas que, comme le code du modèle s'exécute avant que la page ne soit diffusée à l'utilisateur, ces techniques ne peuvent alimenter qu'un contenu initial sur une page. Pour accéder aux
données Apps Script de manière interactive à partir d'une page, utilisez plutôt l'
google.script.run API.
Appeler des fonctions Apps Script à partir d'un modèle
Les scriptlets peuvent appeler n'importe quelle fonction définie dans un fichier de code ou une bibliothèque Apps Script. Cet exemple montre comment extraire des données d'une feuille de calcul dans un modèle, puis créer un tableau HTML à partir de ces données.
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>
Appeler directement les API Apps Script
Vous pouvez également utiliser directement le code Apps Script dans les scriptlets. Cet exemple obtient le même résultat que l'exemple précédent en chargeant les données dans le modèle lui-même plutôt que via une fonction distincte.
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>
Transférer des variables vers des modèles
Enfin, vous pouvez transférer des variables dans un modèle en les attribuant en tant que propriétés
de l'HtmlTemplate objet. Là encore, cet exemple obtient le même résultat que les exemples précédents.
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>
Déboguer des modèles
Les modèles peuvent être difficiles à déboguer, car le code que vous écrivez n'est pas exécuté directement. Au lieu de cela, le serveur transforme votre modèle en code, puis exécute le code résultant.
Si vous ne savez pas comment le modèle interprète vos scriptlets, deux
méthodes de débogage de la
HtmlTemplate classe peuvent vous aider à
mieux comprendre ce qui se passe.
La fonction getCode
La getCode fonction
renvoie une chaîne contenant le code que le serveur crée à partir du modèle.
Si vous
enregistrez le
code, puis le collez dans l'éditeur de script, vous pouvez l'exécuter et le déboguer
comme du code
Apps Script normal.
Voici à nouveau le modèle qui affiche une liste de produits Google, suivi du résultat de getCode :
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 (ÉVALUÉ)
(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('');
})();
La fonction getCodeWithComments
La
getCodeWithComments
fonction est semblable à getCode(), mais renvoie le code évalué sous forme de commentaires
qui apparaissent côte à côte avec le modèle d'origine.
Examiner le code évalué
La première chose que vous remarquerez dans l'un ou l'autre exemple de code évalué est l'objet output implicite créé par la méthode HtmlService.initTemplate. Cette méthode n'est pas documentée, car seuls les modèles eux-mêmes doivent l'utiliser. output est un
objet HtmlOutput spécial avec deux
propriétés nommées de manière inhabituelle, _ et _$, qui sont des raccourcis pour appeler
append et
appendUntrusted.
output possède une autre propriété spéciale, $out, qui fait référence à un objet HtmlOutput normal ne possédant pas ces propriétés spéciales. Le modèle renvoie cet objet normal à la fin du code.
Maintenant que vous comprenez cette syntaxe, vous pouvez suivre le reste du code. Le contenu HTML
en dehors des scriptlets (comme la balise b) est ajouté à l'aide de output._ =
(sans échappement
contextuel), et
les scriptlets sont ajoutés en tant que code JavaScript (avec ou sans échappement contextuel,
selon le type de scriptlet).
Le code évalué conserve les numéros de ligne du modèle. Si vous recevez une erreur lors de l'exécution du code évalué, la ligne correspond au contenu équivalent dans le modèle.
Hiérarchie des commentaires
Étant donné que le code évalué conserve les numéros de ligne, il est possible que les commentaires dans les scriptlets commentent d'autres scriptlets et même du code HTML. Ces exemples montrent quelques effets surprenants des commentaires :
<? 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. */ ?>