📢 Chào mừng các bạn đến với Rcom Dăm Yi blog - Kho tài liệu và giải pháp công nghệ bổ ích! Hệ thống liên tục cập nhật dữ liệu học tập mới.
Bài 19. Tích hợp toàn diện Form, Table & Apps Script (SPA)

Thời gian dùng thử đã hết!

Phần mềm đã vượt quá 15 ngày dùng thử miễn phí. Vui lòng nhập mã bản quyền (License Key) để tiếp tục sử dụng iTeach.

Bài 19. Xây dựng Ứng dụng Quản lý toàn diện (SPA)

1. Kiến thức bài học chuyên sâu

1. Mô hình SPA (Single Page Application) là gì?

Trong các trang web kiểu cũ, mỗi lần bạn bấm "Lưu" hoặc "Chuyển trang", màn hình sẽ chớp trắng một cái để tải lại toàn bộ nội dung. Với SPA, mọi thao tác (Thêm, Xóa, Sửa, Đọc) đều diễn ra trên một trang duy nhất. Dữ liệu được gửi và nhận ngầm ở chế độ nền. Màn hình của người dùng không bao giờ bị tải lại, mang đến cảm giác mượt mà như một phần mềm cài đặt trên máy tính (VD: Facebook, Gmail đều là SPA).

2. Tư duy xử lý Bất đồng bộ (Asynchronous) của google.script.run

Khi JavaScript ở trình duyệt gọi Apps Script (qua google.script.run), nó giống như bạn gọi món ở nhà hàng. Bạn order xong, nhân viên đi vào bếp (Server), còn bạn vẫn có thể ngồi lướt điện thoại (Browser không bị đơ). Khi nấu xong, nhân viên mang món ra (đây chính là lúc withSuccessHandler được kích hoạt).

3. Vòng tuần hoàn dữ liệu (The CRUD Cycle):

  • Bước 1 (Khởi tạo): Vừa mở trang, chạy hàm taiDuLieuBang().
  • Bước 2 (Tương tác): Người dùng điền Form -> Bấm Lưu.
  • Bước 3 (Đóng vòng lặp - Quan trọng nhất): Bắt sự kiện withSuccessHandler báo lưu thành công. Ngay tại đây, ta gọi lại hàm taiDuLieuBang() của Bước 1 để vẽ lại bảng với dữ liệu mới nhất.

2. Bài tập mẫu & Giải phẫu Mã nguồn

Ví dụ: Hệ thống Đăng ký và Quản lý Đề tài KHKT

Đề bài: Xây dựng một giao diện gồm 2 nửa. Trái: Form nhập liệu đề tài KHKT. Phải: Bảng danh sách đề tài. Yêu cầu nhập xong bên trái, bên phải tự động hiện dữ liệu mới.

Phần 1: Code Back-end (Code.gs)

function layDanhSachTuSheet() {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("KHKT");
  // Bỏ qua dòng 1 (tiêu đề), lấy từ dòng 2
  return sheet.getRange(2, 1, sheet.getLastRow() - 1, 3).getValues(); 
}

function luuDeTaiMoi(formObj) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("KHKT");
  sheet.appendRow([formObj.tenDT, formObj.tenHS, formObj.linhVuc]);
  return "Thành công"; 
}
💡 Giải thích Code.gs: Back-end của chúng ta rất đơn giản, chỉ gồm 2 hàm độc lập. layDanhSachTuSheet làm nhiệm vụ Read (Đọc), trả về một mảng 2 chiều. Còn luuDeTaiMoi làm nhiệm vụ Create (Tạo mới), lấy Object từ Form và nối thêm (append) vào dòng cuối cùng của Sheet.

Phần 2: Code Front-end (JavaScript trong file HTML)

// 1. Tự động tải dữ liệu khi trang web vừa load xong
window.onload = taiDuLieuBang;

function taiDuLieuBang() {
  google.script.run.withSuccessHandler(veBang).layDanhSachTuSheet();
}

function veBang(data) {
  let tbody = document.getElementById("myTableBody");
  tbody.innerHTML = ""; // Xóa dữ liệu cũ trước khi đắp cái mới
  
  data.forEach((row, index) => {
    tbody.innerHTML += `<tr><td>${index+1}</td><td>${row[0]}</td><td>${row[1]}</td></tr>`;
  });
}

// 2. Xử lý khi Submit Form
function xuLyThemMoi(formObj) {
  google.script.run
    .withSuccessHandler(function() {
       document.getElementById("formKHKT").reset(); // Xóa trắng form để nhập tiếp
       taiDuLieuBang(); // GỌI LẠI HÀM VẼ BẢNG: Chìa khóa của SPA nằm ở đây!
    })
    .luuDeTaiMoi(formObj);
}
💡 Giải thích JS: Khúc mắc lớn nhất của người mới học là không biết làm sao để bảng cập nhật. Bí quyết nằm ở dòng taiDuLieuBang(); bên trong withSuccessHandler của hàm lưu. Có nghĩa là: "Khi Server báo đã cất dữ liệu thành công, Client tự động gọi lại lệnh kéo dữ liệu mới nhất về và vẽ lại từ đầu". Ta phải gọi tbody.innerHTML = "" để tránh tình trạng dữ liệu cũ bị vẽ lặp lại (nhân bản).

Trải nghiệm Ứng dụng thực tế: Quản lý Đề tài KHKT

Hãy thử điền form bên trái và bấm Gửi, bạn sẽ thấy bảng bên phải tự làm mới mà trình duyệt không hề bị load lại.

Đăng ký đề tài mới

Danh sách đang theo dõi

3. Bài tập tự luyện

Bài tập: Xây dựng Hệ thống Sổ Đầu Bài Điện Tử

Đề bài: Vận dụng kiến thức SPA để tạo sổ đầu bài cho giáo viên bộ môn.

  1. Khởi tạo: Khi mở web, gọi Google Sheets lấy dữ liệu của tất cả các tiết dạy trong ngày hôm nay và vẽ ra bảng.
  2. Cập nhật (Form): Giáo viên chọn Lớp, Môn, Tiết, Tên bài dạy và Xếp loại (A, B, C, D) rồi bấm Lưu.
  3. Thử thách nâng cao (UX): Sau khi bảng tự động refresh để hiện tiết học vừa nhập, hãy viết code CSS/JS để đổi màu nền (Highlight) của hàng mới thêm thành màu vàng sáng trong 3 giây, sau đó từ từ mờ đi thành màu trắng. (Gợi ý: Dùng `setTimeout` trong JS kết hợp đổi `style.backgroundColor`).
Bài 18. Tích hợp HTML, Form & Apps Script (Phần 2)

Thời gian dùng thử đã hết!

Phần mềm đã vượt quá 15 ngày dùng thử miễn phí. Vui lòng nhập mã bản quyền (License Key) để tiếp tục sử dụng iTeach.

Bài 18. Form Nâng cao: Dropdown Động & Cập nhật

1. Kiến thức bài học

1. Dropdown Động (Dynamic Select): Thay vì code cứng các thẻ <option> trong HTML, ta sẽ dùng sự kiện khi trang vừa tải xong (hoặc bấm nút) để gọi Apps Script lấy danh sách từ Sheet (ví dụ: Danh sách thiết bị dạy học), sau đó dùng JavaScript để đổ vào thẻ <select>.

2. Cập nhật dữ liệu (Update Record): Thay vì dùng appendRow() để thêm dòng mới ở cuối bảng, ta sẽ duyệt mảng dữ liệu (vòng lặp for), tìm đúng dòng chứa "Mã cần sửa", sau đó dùng lệnh getRange(row, col).setValue(giaTriMoi) để ghi đè dữ liệu mới.

2. Bài tập mẫu

Ví dụ 1: Tải danh sách thiết bị vào Dropdown

Đề bài: Quản lý danh mục thiết bị rất hay thay đổi. Hãy viết code để Form đăng ký mượn tự động lấy danh sách máy chiếu/laptop từ cột A của Sheet "ThietBi".

Code Apps Script (Code.gs):

function layDanhSachThietBi() {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ThietBi");
  // Lấy cột A, từ dòng 2 đến dòng cuối cùng có dữ liệu
  let data = sheet.getRange(2, 1, sheet.getLastRow() - 1, 1).getValues();
  return data; // Trả về mảng 2 chiều chứa tên các thiết bị
}

Code HTML (Index.html):

<select id="chonThietBi">
  <option value="">Đang tải danh sách...</option>
</select>

<script>
  // Tự động chạy khi trang web tải xong
  window.onload = function() {
    google.script.run
      .withSuccessHandler(doDuLieuVaoSelect)
      .layDanhSachThietBi();
  };

  function doDuLieuVaoSelect(mangThietBi) {
    let select = document.getElementById("chonThietBi");
    select.innerHTML = "<option value=''>-- Vui lòng chọn thiết bị --</option>";
    
    // Duyệt mảng để đắp thẻ option
    mangThietBi.forEach(thietBi => {
      select.innerHTML += `<option value="${thietBi[0]}">${thietBi[0]}</option>`;
    });
  }
</script>

Ví dụ 2: Form Cập nhật tình trạng thiết bị (Update)

Đề bài: Khi một máy in hoặc laptop sửa xong, nhân viên IT cần cập nhật trạng thái từ "Đang hỏng" sang "Hoạt động". Thay vì thêm dòng mới, ta sẽ ghi đè lên dòng cũ dựa vào Mã thiết bị.

Code Apps Script (Code.gs) xử lý Update:

function capNhatTrangThai(formObj) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("QuanLyThietBi");
  let data = sheet.getDataRange().getValues();
  let maCanTim = formObj.maTB;
  
  // Vòng lặp tìm dòng chứa mã thiết bị (Giả sử Mã ở cột A - index 0)
  for (let i = 1; i < data.length; i++) {
    if (data[i][0] == maCanTim) {
      // Cộng 1 vì mảng JS bắt đầu từ 0, nhưng Sheet bắt đầu từ dòng 1
      let rowIndex = i + 1; 
      
      // Cập nhật cột Trạng thái (Giả sử nằm ở cột C - cột số 3)
      sheet.getRange(rowIndex, 3).setValue(formObj.trangThaiMoi);
      
      return "Cập nhật thành công thiết bị: " + maCanTim;
    }
  }
  return "Không tìm thấy thiết bị này!";
}

Mô phỏng Giao diện: Form Cập nhật trạng thái

3. Bài tập tự luyện

Bài tập: Xây dựng Form Chấm công/Duyệt ngày nghỉ

Đề bài: Với vai trò kế toán nhà trường, hãy tạo một Web App duyệt đơn xin nghỉ phép.

  1. Sử dụng Code.gs trả về mảng danh sách các đơn xin nghỉ phép đang có trạng thái "Chờ duyệt" và đổ vào thẻ <select> trên HTML.
  2. Khi chọn một đơn và bấm nút "Phê duyệt", Web App gửi ID đơn đó về Code.gs để tìm đúng dòng và đổi chữ "Chờ duyệt" thành "Đã duyệt".
Bài 17. Tích hợp HTML, Form & Apps Script

Thời gian dùng thử đã hết!

Phần mềm đã vượt quá 15 ngày dùng thử miễn phí. Vui lòng nhập mã bản quyền (License Key) để tiếp tục sử dụng iTeach.

Bài 17. HTML Form & Xử lý Nhập liệu

1. Kiến thức bài học

Thay vì lấy từng thẻ Input rời rạc bằng getElementById(), HTML cung cấp thẻ <form> giúp gom nhóm toàn bộ dữ liệu. Khi đó, ta chỉ cần truyền 1 đối tượng duy nhất chứa toàn bộ form sang Apps Script. Phương pháp này code cực kỳ ngắn gọn và dễ quản lý.

  • Thuộc tính name: Bắt buộc phải thêm thuộc tính name cho các ô input. Tên này sẽ biến thành "Từ khóa" (Key) để Apps Script gọi. (Ví dụ: <input name="hoTen">).
  • Chặn reload trang: Dùng onsubmit="event.preventDefault();" ở thẻ form để ngăn trình duyệt tải lại trang khi bấm gửi.
  • Lấy dữ liệu (Server): Trong Code.gs, truy xuất bằng cách gọi doiTuongForm.tenThuocTinhName.

2. Bài tập mẫu

Ví dụ 1: Form Đăng ký mượn phòng máy tính

Đề bài: Tạo form cho giáo viên đăng ký mượn phòng thực hành Tin học. Gửi thông tin (Họ tên, Phòng, Tiết dạy) về Google Sheets bằng kỹ thuật gom đối tượng Form.

Code HTML (Index.html):

<!-- Truyền this (tức là toàn bộ form) vào hàm JavaScript -->
<form id="formMuonPhong" onsubmit="event.preventDefault(); guiDuLieu(this);">
  <input type="text" name="gvTen" placeholder="Họ tên Giáo viên" required>
  <input type="text" name="tietDay" placeholder="Tiết mượn (VD: Tiết 3, 4)" required>
  <button type="submit">Đăng ký</button>
</form>

<script>
  function guiDuLieu(formObject) {
    google.script.run
      .withSuccessHandler(function(res) { alert(res); })
      .xuLyDangKy(formObject); // Đẩy toàn bộ form sang Apps Script
  }
</script>

Code Apps Script (Code.gs):

function xuLyDangKy(formObj) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  
  // Gọi dữ liệu bằng cách chấm tới thuộc tính 'name' ở HTML
  let rowData = [
    new Date(),
    formObj.gvTen,
    formObj.tietDay
  ];
  
  sheet.appendRow(rowData);
  return "Đăng ký thành công!";
}

Ví dụ 2: Tối ưu Trải nghiệm người dùng (UX) - Form Báo hỏng thiết bị

Đề bài: Làm một Form báo cáo sự cố (Lỗi Màn hình xanh BSOD, Kẹt giấy máy in...). Cần xử lý UX: Đổi chữ nút thành "Đang gửi...", vô hiệu hóa nút để tránh bấm 2 lần, và xóa trắng Form sau khi gửi xong.

Mô phỏng Giao diện: Hệ thống báo sự cố Kỹ thuật

✓ Đã ghi nhận sự cố. Kỹ thuật viên sẽ kiểm tra sớm nhất!

Code JavaScript xử lý UX (Tham khảo):

<script>
  function xuLyForm(formObj) {
    // 1. Khóa form, hiện Spinner
    document.getElementById("btnSubmit").disabled = true;
    document.getElementById("spinner").style.display = "inline-block";
    document.getElementById("btnText").innerText = "Đang gửi dữ liệu...";

    google.script.run
      .withSuccessHandler(function(res) { 
         // 2. Xử lý sau khi thành công
         document.getElementById("successMsg").style.display = "block";
         document.getElementById("demoForm").reset(); // Xóa trắng form
         
         // 3. Khôi phục nút bấm
         document.getElementById("btnSubmit").disabled = false;
         document.getElementById("spinner").style.display = "none";
         document.getElementById("btnText").innerText = "Gửi Báo Cáo";
      })
      .ghiNhanSuCo(formObj);
  }
</script>

3. Bài tập tự luyện

Bài tập: Thêm xác thực dữ liệu (Validation)

Đề bài: Trong hệ thống kiểm kê sổ sách kế toán của trường, bạn cần viết một form nhập số tiền thanh toán hóa đơn vật tư.

  1. Thêm trường <input type="number" name="soTien">.
  2. Trước khi gọi google.script.run, hãy dùng JavaScript kiểm tra: Nếu số tiền nhỏ hơn 0, dùng lệnh alert("Số tiền không hợp lệ!") và dừng lại bằng lệnh return;.
  3. Nếu số tiền hợp lệ mới gọi Apps Script để lưu vào báo cáo tài chính.
Bài 16. Tích hợp HTML, Google Sheet & Apps Script (Phần 5)

Thời gian dùng thử đã hết!

Phần mềm đã vượt quá 15 ngày dùng thử miễn phí. Vui lòng nhập mã bản quyền (License Key) để tiếp tục sử dụng iTeach.

Bài 16. Bảng Dữ liệu (Phần 5): Tìm kiếm & Tương tác

1. Kiến thức bài học

Sau khi đã đổ được dữ liệu từ Apps Script ra Bảng HTML (Table), hai tính năng được mong chờ nhất trong các hệ thống quản lý trường học là:

  • Thanh tìm kiếm (Client-side Search): Sử dụng sự kiện onkeyup của JavaScript để bắt từng phím người dùng gõ vào ô tìm kiếm. Thuật toán sẽ duyệt qua các thẻ <tr>, so sánh chuỗi và ẩn (display: none) những hàng không khớp.
  • Nút Hành động (Action Buttons): Chèn một thẻ <button> vào một cột (ví dụ cột Cuối cùng) khi vòng lặp tạo bảng. Gắn mã định danh (như Mã học sinh) vào thuộc tính của nút để gọi google.script.run xử lý tác vụ Xóa, Sửa.

2. Bài tập mẫu

Ví dụ 1: Tìm kiếm trực tiếp trên bảng

Đề bài: Tạo một ô nhập liệu (Input). Bất cứ khi nào giáo viên gõ tên học sinh, bảng danh sách nghiên cứu KHKT bên dưới sẽ tự động lọc ngay lập tức mà không cần tải lại trang.

Code HTML / JavaScript (Thêm vào trên thẻ table):

<input type="text" id="timKiem" onkeyup="locDuLieu()" placeholder="🔍 Nhập tên học sinh để tìm kiếm...">

<script>
  function locDuLieu() {
    // Lấy giá trị đang gõ và chuyển thành chữ in hoa để so sánh
    let input = document.getElementById("timKiem");
    let filter = input.value.toUpperCase();
    
    // Lấy bảng và danh sách các thẻ <tr>
    let table = document.getElementById("bangDanhSach");
    let tr = table.getElementsByTagName("tr");

    // Duyệt qua các hàng (Bỏ qua hàng 0 là tiêu đề)
    for (let i = 1; i < tr.length; i++) {
      let td = tr[i].getElementsByTagName("td")[0]; // Lấy cột Tên (Cột đầu tiên)
      if (td) {
        let txtValue = td.textContent || td.innerText;
        // Nếu tên chứa từ khóa tìm kiếm -> Hiển thị, ngược lại -> Ẩn đi
        if (txtValue.toUpperCase().indexOf(filter) > -1) {
          tr[i].style.display = "";
        } else {
          tr[i].style.display = "none";
        }
      }       
    }
  }
</script>

Ví dụ 2: Thêm nút "Xóa" gọi về Apps Script

Đề bài: Khi vòng lặp JS đắp dữ liệu vào bảng, hãy thêm một cột "Thao tác" chứa nút Xóa. Khi bấm nút, gửi Mã học sinh về Server để xóa dòng trong Google Sheets.

Khúc Code JS lúc tạo Bảng (Client):

  dataArray.forEach(row => {
    html += `
      <tr id="hang-${row[0]}">
        <td>${row[0]}</td>  <!-- Mã HS -->
        <td>${row[1]}</td>  <!-- Tên -->
        <td>
          <button onclick="xoaHocSinh('${row[0]}')">Xóa</button>
        </td>
      </tr>
    `;
  });

  function xoaHocSinh(maHS) {
    if(confirm("Bạn có chắc muốn xóa " + maHS + " không?")) {
      google.script.run.xoaTrenSheet(maHS); // Gọi Apps Script
      document.getElementById("hang-" + maHS).style.display = "none"; // Ẩn trên giao diện tạm thời
    }
  }

Mô phỏng Giao diện: Tìm kiếm và Tương tác Bảng

Danh sách học sinh tham gia dự án KHKT (THPT Phan Chu Trinh):

Mã HS Họ và Tên Dự án KHKT Thao tác
HS01 Kpă Su Điểm danh QR
HS02 Nay Phoan Điểm danh QR
HS03 Trần Văn Bình Phần mềm thi trắc nghiệm
Không tìm thấy học sinh nào!

3. Bài tập tự luyện

Bài tập: Xây dựng hệ thống quản lý mượn trả thiết bị

Đề bài: Là người quản lý thiết bị trường học, hãy tạo một Web App hiển thị danh sách thiết bị đang được mượn.

  1. Thêm thanh tìm kiếm (như Ví dụ 1) để tìm nhanh theo "Tên giáo viên mượn".
  2. Tạo một nút "Đã Trả" thay vì nút "Xóa" cho mỗi hàng.
  3. Khi click nút "Đã Trả", dùng google.script.run gửi Mã thiết bị về Code.gs để hàm Code.gs cập nhật trạng thái trong Sheet thành "Hoàn thành", đồng thời cập nhật hàng đó trên giao diện sang màu xám.
Bài 15. Tích hợp HTML, Google Sheet & Apps Script (Phần 4)

Thời gian dùng thử đã hết!

Phần mềm đã vượt quá 15 ngày dùng thử miễn phí. Vui lòng nhập mã bản quyền (License Key) để tiếp tục sử dụng iTeach.

Bài 15. Hiển thị Bảng dữ liệu (Dynamic Table) lên Web App

1. Kiến thức bài học

Để hiển thị một danh sách học sinh (hoặc bảng điểm) từ Google Sheets lên Web App, chúng ta cần thực hiện 3 bước:

  1. Server (Code.gs): Dùng getValues() đọc toàn bộ dữ liệu thành mảng 2 chiều và return mảng đó.
  2. Client (HTML/JS): Dùng google.script.run để gọi hàm trên Server và nhận mảng dữ liệu trả về.
  3. Render (Tạo giao diện): Dùng vòng lặp for hoặc forEach trong JavaScript duyệt qua mảng, tạo ra các chuỗi thẻ <tr> (hàng) và <td> (cột), sau đó nhúng vào thẻ <tbody> của bảng HTML bằng lệnh innerHTML.

2. Bài tập mẫu

Ví dụ 1: Đổ dữ liệu Bảng điểm cơ bản

Đề bài: Đọc dữ liệu điểm Toán và Tin học của lớp từ Sheets và hiển thị thành một bảng trên trang Web.

Ý tưởng: Server trả về mảng. HTML chuẩn bị sẵn thẻ <table> với ID là bangDiem. JS sẽ nối chuỗi HTML đắp vào bảng.

Code Apps Script (Code.gs):

function layDuLieuDiem() {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DiemThi");
  // Bỏ qua hàng 1 (tiêu đề), lấy từ hàng 2 đến hết
  let data = sheet.getRange(2, 1, sheet.getLastRow()-1, 3).getValues();
  return data; // Trả mảng 2 chiều về cho Client
}

Code HTML (Index.html):

<table id="bangDiem" border="1"></table>

<script>
  // Gọi API ngay khi web vừa tải xong
  google.script.run
    .withSuccessHandler(veBang)
    .layDuLieuDiem();

  function veBang(dataArray) {
    let html = "<tr><th>Họ tên</th><th>Điểm Toán</th><th>Điểm Tin</th></tr>";
    
    // Duyệt qua từng hàng dữ liệu
    for (let i = 0; i < dataArray.length; i++) {
      html += "<tr>";
      html += "<td>" + dataArray[i][0] + "</td>";
      html += "<td>" + dataArray[i][1] + "</td>";
      html += "<td>" + dataArray[i][2] + "</td>";
      html += "</tr>";
    }
    
    document.getElementById("bangDiem").innerHTML = html;
  }
</script>

Mô phỏng (Ví dụ 1): Render Bảng Điểm

Ví dụ 2: Ứng dụng vòng lặp forEach kết hợp Template String (ES6)

Đề bài: Cùng bài toán trên, nhưng ta sẽ viết code JavaScript ngắn gọn hơn, dễ đọc hơn bằng cách sử dụng vòng lặp forEach và dấu backtick ( ` ) của ES6.

Code JavaScript (Trong thẻ script HTML):

function veBangHienDai(dataArray) {
  let tbody = document.getElementById("noiDungBang");
  let html = "";

  // Sử dụng forEach và Template String (Dấu ` )
  dataArray.forEach(row => {
    html += `
      <tr>
        <td>${row[0]}</td>
        <td>${row[1]}</td>
        <td>${row[2]}</td>
      </tr>
    `;
  });

  tbody.innerHTML = html;
}

Giải thích: Phương pháp sử dụng ${biến} giúp bạn không cần phải viết nối chuỗi bằng hàng loạt dấu cộng + gây rối mắt. Điều này cực kỳ hữu ích khi bảng HTML của bạn có chứa các nút bấm (Button) hoặc hình ảnh phức tạp bên trong ô.

3. Bài tập tự luyện

Bài tập: Hiển thị nhật ký điểm danh QR Code

Đề bài: Bạn đang phát triển hệ thống Điểm danh qua mã QR cho trường THPT Phan Chu Trinh. Dữ liệu từ Sheet lưu theo cấu trúc: Cột A (Thời gian quét), Cột B (Mã học sinh), Cột C (Họ tên). Hãy viết một trang Web App đọc mảng này và đổ lên một Bảng HTML.

Yêu cầu bổ sung:

  • Nếu thời gian quét lớn hơn 07:15, hãy dùng thẻ <span style="color:red"> bọc tên học sinh lại để đánh dấu "Đi trễ". (Gợi ý: Dùng lệnh if bên trong vòng lặp tạo HTML).
Bài 15. Tích hợp HTML, Google Sheet & Apps Script (Giao tiếp hai chiều)

Thời gian dùng thử đã hết!

Phần mềm đã vượt quá 15 ngày dùng thử miễn phí. Vui lòng nhập mã bản quyền (License Key) để tiếp tục sử dụng iTeach.

Bài 15. Giao tiếp Web & Apps Script với google.script.run

1. Kiến thức bài học: Cơ chế Client - Server

Trong một ứng dụng Web App tạo bằng Apps Script, mã HTML/JS chạy trên trình duyệt của người dùng (Client), trong khi dữ liệu Google Sheets nằm trên máy chủ (Server). Để chúng nói chuyện được với nhau, Google cung cấp API vô cùng mạnh mẽ: google.script.run.

  • Gửi dữ liệu lên Server: google.script.run.TenHam_Trong_CodeGS(duLieu).
  • Nhận kết quả trả về: Sử dụng .withSuccessHandler(hamXuLy) để đón dữ liệu từ Server gửi ngược lại Client một cách bất đồng bộ (không cần tải lại trang).

2. Bài tập mẫu

Ví dụ 1: Form Gửi Dữ liệu (Submit)

Đề bài: Tạo Form HTML cho phép học sinh nhập tên và tên dự án KHKT. Khi bấm "Gửi", dữ liệu được truyền sang hàm luuDuAn() trong Code.gs để lưu vào Sheet, sau đó hiển thị thông báo thành công.

Code Apps Script (Code.gs):

function luuDuAn(tenHS, tenDuAn) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  // Ghi dữ liệu vào dòng cuối cùng
  sheet.appendRow([new Date(), tenHS, tenDuAn]);
  
  // Trả về kết quả cho HTML
  return "Đã lưu thành công dự án của " + tenHS;
}

Code HTML (Index.html):

<input type="text" id="hsName" placeholder="Tên học sinh (VD: Nay Phoan)">
<input type="text" id="prjName" placeholder="Tên dự án">
<button onclick="guiForm()">Gửi Đăng Ký</button>

<script>
  function guiForm() {
    let hs = document.getElementById("hsName").value;
    let prj = document.getElementById("prjName").value;
    
    // Gọi hàm Apps Script và đợi kết quả trả về bằng withSuccessHandler
    google.script.run
      .withSuccessHandler(function(ketQua) {
         alert(ketQua); // Hiển thị chữ "Đã lưu thành công..."
      })
      .luuDuAn(hs, prj);
  }
</script>

Mô phỏng: Form Gửi Dữ Liệu


Ví dụ 2: Tra cứu dữ liệu từ Sheet (Fetch)

Đề bài: Xây dựng công cụ tra cứu điểm. Nhập mã học sinh trên web, Client sẽ yêu cầu Server tìm trong Sheet. Server tìm xong trả về số điểm để Client hiển thị lên màn hình.

Code Apps Script (Code.gs):

function timKiemDiem(maHS) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  let data = sheet.getDataRange().getValues();
  
  // Tìm kiếm trong mảng 2 chiều
  for (let i = 0; i < data.length; i++) {
    if (data[i][0] == maHS) {
      return data[i][1]; // Trả về điểm ở cột B
    }
  }
  return "Không tìm thấy học sinh!";
}

Code HTML (Index.html):

<script>
  function traCuu() {
    let ma = document.getElementById("maHocSinh").value;
    
    google.script.run
      .withSuccessHandler(function(diem) {
         document.getElementById("ketQuaDiem").innerHTML = "Điểm của bạn là: " + diem;
      })
      .timKiemDiem(ma);
  }
</script>

Mô phỏng: Tra cứu điểm trực tuyến

(Mã hợp lệ: HS01, HS02)


3. Bài tập tự luyện

Bài tập: Xử lý lỗi (Error Handling)

Đề bài: Bên cạnh .withSuccessHandler(), hệ thống còn hỗ trợ .withFailureHandler() để bắt các lỗi phát sinh (ví dụ: đứt mạng, lỗi code trên server). Hãy viết lại đoạn mã ở Ví dụ 1, thêm cơ chế thông báo lỗi cho người dùng nếu quá trình lưu dự án thất bại.

Gợi ý:

google.script.run
  .withSuccessHandler(thanhCong)
  .withFailureHandler(function(loi) { alert("Có lỗi xảy ra: " + loi.message); })
  .luuDuAn(hs, prj);