Layanan HTML: HTML template

Anda dapat menggabungkan kode Apps Script dan HTML untuk menghasilkan halaman dinamis dengan upaya minimal. Jika Anda telah menggunakan bahasa template yang menggabungkan kode dan HTML, seperti PHP, ASP, atau JSP, sintaksisnya akan terasa familier.

Skriplet

Template Apps Script dapat berisi tiga tag khusus, yang disebut skriplet. Di dalam scriptlet, Anda dapat menulis kode apa pun yang akan berfungsi dalam file Apps Script normal: skriplet dapat memanggil fungsi yang ditentukan dalam file kode lain, mereferensikan variabel global, atau menggunakan Apps Script API. Anda bahkan dapat menentukan fungsi dan variabel dalam skriplet, dengan peringatan bahwa fungsi dan variabel tersebut tidak dapat dipanggil oleh fungsi yang ditentukan dalam file kode atau template lainnya.

Jika Anda menempelkan contoh di bawah ke editor skrip, konten tag <?= ... ?> (scriptlet pencetakan) akan muncul dalam cetak miring. Kode yang dicetak miring tersebut berjalan di server sebelum halaman ditayangkan kepada pengguna. Karena kode scriptlet dieksekusi sebelum halaman ditayangkan, kode ini hanya dapat berjalan satu kali per halaman. Tidak seperti fungsi JavaScript sisi klien atau Apps Script yang Anda panggil melalui google.script.run, skriplet 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 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 skrip dan mengonversi template menjadi objek HtmlOutput yang dapat ditayangkan oleh skrip kepada pengguna.

Scriptlet standar

Scriptlet standar, yang menggunakan sintaksis <? ... ?>, mengeksekusi kode tanpa menghasilkan konten ke halaman secara eksplisit. Namun, seperti yang ditunjukkan contoh ini, hasil kode di dalam skriplet masih dapat memengaruhi konten HTML di luar skriplet:

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>

Mencetak skriplet

Scriptlet pencetakan, yang menggunakan sintaksis <?= ... ?>, menampilkan hasil kodenya ke dalam halaman menggunakan escaping kontekstual.

Escape kontekstual berarti bahwa Apps Script melacak konteks output di halaman — di dalam atribut HTML, di dalam tag script sisi klien, atau di tempat lainnya — dan otomatis menambahkan karakter escape untuk melindungi dari serangan pembuatan skrip lintas situs (XSS).

Dalam contoh ini, skriplet pencetakan pertama menghasilkan string secara langsung; skriplet ini diikuti dengan skriplet standar yang menyiapkan array dan loop, diikuti oleh scriptlet pencetakan lainnya untuk menghasilkan isi 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 skriplet pencetakan hanya menghasilkan nilai pernyataan pertamanya; pernyataan lainnya akan berperilaku seolah-olah dimuat dalam skrip standar. Jadi, misalnya, skriplet <?= 'Hello, world!'; 'abc' ?> hanya mencetak "Hello, world!" (Halo dunia)

Mencetak otomatis skriplet

Mencetak otomatis skriplet, yang menggunakan sintaksis <?!= ... ?>, mirip seperti mencetak skriplet, kecuali bahwa skrip tersebut menghindari escape kontekstual.

Escape 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 disisipkan persis seperti yang ditentukan.

Sebagai aturan umum, gunakan skriplet pencetakan, bukan skriplet cetak paksa, kecuali jika Anda mengetahui bahwa Anda harus mencetak HTML atau JavaScript tanpa perubahan.

Kode Apps Script di skriplet

Scriptlet tidak dibatasi untuk menjalankan JavaScript normal. Anda juga dapat menggunakan salah satu dari tiga teknik berikut untuk memberi template Anda akses ke data Apps Script.

Namun, perlu diingat bahwa karena kode template dieksekusi sebelum halaman ditayangkan kepada pengguna, teknik ini hanya dapat melakukan feed konten awal ke sebuah halaman. Untuk mengakses data Apps Script dari halaman secara interaktif, gunakan google.script.run API.

Memanggil fungsi Apps Script dari template

Scriptlet dapat memanggil fungsi apa pun yang ditentukan dalam library atau file 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 langsung di skriplet. Contoh ini memberikan hasil yang sama seperti contoh sebelumnya dengan memuat data dalam template itu sendiri, bukan melalui fungsi yang 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>

Mengirim variabel ke template

Terakhir, Anda dapat mengirim variabel ke dalam template dengan menetapkannya sebagai properti dari objek HtmlTemplate. Sekali lagi, contoh ini memberikan 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 proses debug

Template dapat menjadi sulit untuk di-debug karena kode yang Anda tulis tidak dieksekusi secara langsung. Sebagai gantinya, server akan mengubah template Anda menjadi kode, lalu mengeksekusi kode yang dihasilkan tersebut.

Jika cara template menafsirkan skriplet Anda tidak jelas, dua metode proses debug di class HtmlTemplate dapat membantu Anda lebih memahami apa yang terjadi.

getCode()

getCode() menampilkan string yang berisi kode yang dibuat server dari template. Jika mencatat kode ke dalam log, lalu menempelkannya ke editor skrip, Anda dapat menjalankannya dan men-debug-nya seperti kode Apps Script normal.

Berikut adalah template sederhana yang menampilkan lagi daftar produk Google, 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>

CATAT (EVALUASI)

(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() mirip dengan getCode(), tetapi menampilkan kode yang dievaluasi sebagai komentar yang muncul berdampingan dengan template asli.

Panduan kode yang dievaluasi

Hal pertama yang akan Anda lihat di 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 bernama tidak biasa, _ dan _$, yang merupakan singkatan untuk memanggil append() dan appendUntrusted().

output memiliki satu properti khusus lagi, $out, yang mengacu pada objek HtmlOutput reguler yang tidak memiliki properti khusus ini. Template akan menampilkan objek normal tersebut di akhir kode.

Setelah Anda memahami sintaksis ini, kode lainnya seharusnya cukup mudah diikuti. Konten HTML di luar skriplet (seperti tag b) ditambahkan menggunakan output._ = (tanpa escaping kontekstual), dan skriplet ditambahkan sebagai JavaScript (dengan atau tanpa escaping kontekstual, bergantung pada jenis skriplet).

Perhatikan bahwa kode yang dievaluasi mempertahankan nomor baris dari template. Jika Anda mengalami error saat menjalankan kode yang dievaluasi, baris tersebut akan sesuai dengan konten yang setara dalam template.

Hierarki komentar

Karena kode yang dievaluasi mempertahankan nomor baris, komentar di dalam skrip mungkin dapat berkomentar dengan skriplet lain dan bahkan kode HTML. Contoh berikut menunjukkan beberapa efek komentar yang mengejutkan:

<? 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. */ ?>