Anda dapat menggunakan template untuk menggabungkan kode Google Apps Script dan HTML untuk membuat halaman dinamis dengan mudah. Jika Anda pernah menggunakan bahasa template yang mencampur kode dan HTML, seperti PHP, ASP, atau JSP, sintaksisnya akan terasa familiar.
Scriptlet
Template Apps Script dapat berisi tiga tag khusus yang disebut scriptlet. Di dalam scriptlet, Anda dapat menulis kode apa pun yang berfungsi dalam file Apps Script normal: scriptlet dapat memanggil fungsi yang ditentukan dalam file kode lain, merujuk variabel global, atau menggunakan salah satu API Apps Script. Anda bahkan dapat menentukan fungsi dan variabel dalam scriptlet, dengan catatan bahwa fungsi dan variabel tersebut tidak dapat dipanggil oleh fungsi yang ditentukan dalam file kode atau template lain.
Jika Anda menempelkan contoh berikut ke editor skrip, konten tag
<?= ... ?> (print scriptlet) akan muncul dalam
huruf miring. Kode ini berjalan di server sebelum halaman ditayangkan kepada pengguna. Karena kode scriptlet dieksekusi sebelum halaman ditayangkan, kode tersebut hanya dapat dijalankan satu kali per halaman. Tidak seperti fungsi JavaScript atau
Apps Script sisi klien yang Anda panggil melalui
google.script.run, scriptlet tidak dapat
dieksekusi lagi setelah halaman dimuat.
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>
Perhatikan bahwa fungsi doGet untuk HTML yang dibuat dengan template berbeda dengan contoh
untuk membuat dan menayangkan HTML dasar. Fungsi
yang ditampilkan di sini menghasilkan
objek HtmlTemplate dari file
HTML, lalu memanggil
metode evaluate untuk
mengeksekusi scriptlet dan mengonversi template menjadi
objek HtmlOutput yang dapat ditayangkan skrip
kepada pengguna.
Scriptlet standar
Scriptlet standar, yang menggunakan sintaksis <? ... ?>, menjalankan kode tanpa
secara eksplisit menampilkan konten ke halaman. Namun, seperti yang ditunjukkan contoh ini, hasil kode di dalam scriptlet masih dapat memengaruhi konten HTML di luar 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>
Mencetak scriptlet
Scriptlet pencetakan, yang menggunakan sintaksis <?= ... ?>, menampilkan hasil
kodenya ke halaman menggunakan pelepasan kontekstual.
Pelepasan kontekstual berarti Apps Script melacak konteks output di halaman — di dalam atribut HTML, di dalam tag script sisi klien, atau di tempat lain — dan secara otomatis menambahkan karakter escape untuk melindungi dari serangan pembuatan skrip lintas situs (XSS).
Dalam contoh ini, scriptlet pencetakan pertama menghasilkan string secara langsung; diikuti dengan scriptlet standar yang menyiapkan array dan loop, lalu diikuti dengan scriptlet pencetakan lain untuk menghasilkan konten array.
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>
Perhatikan bahwa scriptlet pencetakan hanya menampilkan nilai pernyataan pertamanya;
pernyataan yang tersisa berperilaku seolah-olah berada dalam scriptlet
standar. Jadi, misalnya, scriptlet <?= 'Hello, world!'; 'abc' ?> hanya
mencetak "Hello, world!"
Scriptlet pencetakan paksa
Scriptlet pencetakan paksa, yang menggunakan sintaksis <?!= ... ?>, seperti scriptlet
pencetakan, kecuali bahwa scriptlet ini menghindari pelepasan kontekstual.
Pelepasan kontekstual penting jika skrip Anda mengizinkan input pengguna yang tidak tepercaya. Sebaliknya, Anda harus mencetak paksa jika output scriptlet Anda sengaja berisi HTML atau skrip yang ingin Anda sisipkan persis seperti yang ditentukan.
Sebagai aturan umum, gunakan scriptlet pencetakan, bukan scriptlet pencetakan paksa, kecuali jika Anda tahu bahwa Anda perlu mencetak HTML atau JavaScript tanpa diubah.
Kode Apps Script dalam scriptlet
Scriptlet tidak terbatas pada menjalankan JavaScript normal; Anda juga dapat menggunakan salah satu dari tiga teknik berikut untuk memberikan akses template ke data Apps Script.
Namun, ingatlah bahwa karena kode template dieksekusi sebelum halaman ditayangkan kepada pengguna, teknik ini hanya dapat memasukkan konten awal ke halaman. Untuk mengakses data Apps Script dari halaman secara interaktif, gunakan API google.script.run.
Memanggil fungsi Apps Script dari template
Scriptlet dapat memanggil fungsi apa pun yang ditentukan dalam file atau library kode Apps Script. Contoh ini menunjukkan salah satu cara untuk menarik data dari spreadsheet ke dalam template, lalu membuat tabel HTML dari data tersebut.
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>
Memanggil API Apps Script secara langsung
Anda juga dapat menggunakan kode Apps Script secara langsung di scriptlet. Contoh ini mencapai hasil yang sama dengan contoh sebelumnya dengan memuat data dalam template itu sendiri, bukan melalui fungsi terpisah.
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>
Mendorong variabel ke template
Terakhir, Anda dapat mendorong variabel ke dalam template dengan menetapkannya sebagai properti
objek HtmlTemplate. Sekali
lagi, contoh ini menghasilkan hasil yang sama dengan contoh sebelumnya.
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>
Template debug
Proses debug template bisa jadi sulit karena kode yang Anda tulis tidak dieksekusi secara langsung. Sebagai gantinya, server akan mengubah template Anda menjadi kode, lalu menjalankan kode yang dihasilkan tersebut.
Jika tidak jelas bagaimana template menafsirkan scriptlet Anda, dua metode proses debug di class HtmlTemplate dapat membantu Anda lebih memahami apa yang terjadi.
Fungsi getCode
Fungsi getCode
menampilkan string yang berisi kode yang dibuat server dari template.
Jika Anda
mencatat
kode, lalu menempelkannya ke editor skrip, Anda dapat menjalankannya dan men-debugnya seperti kode Apps Script biasa.
Berikut adalah template yang menampilkan daftar produk Google lagi,
diikuti dengan hasil 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 (DIEVALUASI)
(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('');
})();
Fungsi getCodeWithComments
Fungsi
getCodeWithComments
mirip dengan getCode(), tetapi menampilkan kode yang dievaluasi sebagai komentar
yang muncul berdampingan dengan template asli.
Menelusuri kode yang dievaluasi
Hal pertama yang akan Anda perhatikan dalam kedua contoh kode yang dievaluasi adalah objek output implisit yang dibuat oleh metode HtmlService.initTemplate. Metode ini tidak didokumentasikan karena hanya template itu sendiri yang perlu menggunakannya. output adalah objek
HtmlOutput khusus dengan dua
properti yang namanya tidak biasa, _ dan _$, yang merupakan singkatan untuk memanggil
append dan
appendUntrusted.
output memiliki satu properti khusus lagi, $out, yang merujuk ke objek
HtmlOutput reguler yang tidak memiliki properti khusus ini. Template
mengembalikan objek normal tersebut di akhir kode.
Setelah memahami sintaksis ini, Anda dapat mengikuti kode lainnya. Konten
HTML di luar scriptlet (seperti tag b) ditambahkan menggunakan output._ =
(tanpa escaping kontekstual), dan
scriptlet ditambahkan sebagai JavaScript (dengan atau tanpa escaping kontekstual,
bergantung pada jenis scriptlet).
Kode yang dievaluasi mempertahankan nomor baris dari template. Jika Anda mendapatkan error saat menjalankan kode yang dievaluasi, baris tersebut sesuai dengan konten yang setara dalam template.
Hierarki komentar
Karena kode yang dievaluasi mempertahankan nomor baris, komentar di dalam scriptlet dapat mengomentari scriptlet lain dan bahkan kode HTML. Contoh-contoh ini menunjukkan beberapa efek mengejutkan dari komentar:
<? 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. */ ?>