- vừa được xem lúc

Tạo data table web app lấy dữ liệu từ Google Sheets sử dụng Apps Script

0 0 266

Người đăng: Viking

Theo Viblo Asia

Google Sheets là công cụ tuyệt vời để lưu trữ bảng tính trực tuyến, bạn có thể truy cập bảng tính bất kỳ lúc nào ở bất kỳ đâu và luôn sẵn sàng để chia sẻ với người khác.

Nếu bạn chỉ muốn chia sẻ một phần của bảng tính, tạo một sheet mới và dùng hàm importRange có thể đã đáp ứng yêu cầu của bạn. Tuy nhiên, nếu bạn muốn cung cấp một giao diện trực quan hơn cho người dùng để thực hiện các thao tác như sort, search, highlight, paging... thì bạn có thể viết web app sử dụng Apps Script của Google cung cấp.

Bài này gồm 2 phần. Phần 1 chúng ta sẽ hiển thị toàn bộ dữ liệu mỗi khi load web app. Phần 2 chúng ta sẽ tạo chức năng Search và chỉ hiển thị đúng dữ liệu mà người dùng yêu cầu. Lưu ý, bài này dành cho beginner.

1. Hiển thị data table

Để tạo table, chúng ta có thể sử dụng JavaScript thuần, nhưng mình sử dụng Data Tables jQuery plug-in để việc tạo table dễ dàng hơn và có sẵn nhiều chức năng.

Mình tìm table jQuery plug-in trên Google và thấy plug-in này hiện ra đầu tiên nên dùng luôn. Nếu bạn biết plug-in nào hay ho hơn thì hãy cho mình biết nhé.

Chúng ta cùng xem qua thành quả trước khi bắt tay vào viết code.

Code Apps Script

Theo hướng dẫn của Google, chúng ta cần hàm doGet() hoặc doPost() có trả về HTML Service object để tạo giao diện cho web app. Chúng ta tách file CSS, JavaScript với file HTML theo hướng dẫn best practices của Google bằng hàm include().

// file Code.gs
function doGet(e) { return HtmlService.createTemplateFromFile('Index.html') .evaluate();
} function include(filename) { return HtmlService.createHtmlOutputFromFile(filename) .getContent();
}

Index.html

Trong file HTML, chúng ta sẽ tạo thẻ <table> với id="table" để render table sau khi lấy dữ liệu từ file Google Sheets. Các bạn lưu ý, Data Tables jQuery là 1 plug-in của jQuery nên đừng quên chèn link CDN jQuery vào file HTML trước khi chèn link plug-in.

Bây giờ mình đã biết chèn link file JavaScript cũng phải đúng thứ tự thì code máy chạy. Hồi đó tự học nên không có ai dạy về điều này hết.

<!DOCTYPE html>
<html> <head> <base target="_top"> <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.24/css/jquery.dataTables.css"> <?!= include('Stylesheet') ?> </head> <body> <div class="heading"> <h1>Invoice</h1> <p class="grey">Invoice data from the spreadsheet, use <a href="https://datatables.net/" target="_blank"> Data Table jQuery </a> plug-in to render table.</p> </div> <div> <table id="table" class="display" width="75%"></table> </div> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.js"> </script> <?!= include('JavaScript') ?> </body>
</html>

Code JavaScript

Chúng ta dùng hàm ready của jQuery để thực thi một hàm callback khi DOM đã sẵn sàng. Chúng ta sẽ sử dụng class google.script.run để chạy hàm Apps Script khi ở client-side.

Để khởi tạo DataTable instance thì chúng ta cần truyền vào columns, data và một số option khác các bạn có thể tham khảo tại https://datatables.net/.

// File JavaScript.html
<script> $().ready(function(){ google.script.run.withSuccessHandler(showDataTable) .getAllData(); }); function showDataTable(dataTable) { var header = []; dataTable.header.forEach(item => { header.push({title: item}); }) $('#table').DataTable({ data: dataTable.data, columns: header, searching: false, info: false }) }
</script>

Code server- side

Ở server-side (file Code.gs) chúng ta sẽ viết hàm getAllData() để trả về dữ liệu để tạo bảng.

// File Code.gs
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Invoice');
function doGet(e) { ...
} function include(filename) { ...
} function getAllData() { var range = sheet.getRange(2, 1, sheet.getLastRow()-1, sheet.getLastColumn()); var values = range.getValues(); return { header: getHeaderArr(), data: values }
} function getHeaderArr() { var headerRowPosition = 1; var range = sheet.getRange(headerRowPosition, 1, 1, sheet.getLastColumn()); return range.getValues()[0];
}

Thêm loader

Mỗi lần load dữ liệu có thể mất vài giây nên chúng ta sẽ thêm loader để báo hiệu cho người dùng biết là dữ liệu đang được load.

<!-- File Index.html -->
...
<div id="loading">
</div>
...

Chúng ta sẽ tạo một vùng có id là loading để chèn loader. Code CSS được tham khảo từ website https://www.w3schools.com/.

<!-- File Stylesheet.htm l-->
<style> #loading { margin: auto; border: 16px solid #f3f3f3; border-radius: 50%; border-top: 16px solid #3498db; width: 120px; height: 120px; -webkit-animation: spin 2s linear infinite; /* Safari */ animation: spin 2s linear infinite; } /* Safari */ @-webkit-keyframes spin { 0% { -webkit-transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
</style>

Chúng ta sẽ ẩn loader này đi khi dữ liệu đã được tải xong.

 function showDataTable(dataTable) { $('#loading').hide(); ...
}

Kết quả

Như vậy chúng ta đã lấy được dữ liệu từ Google Sheets và tạo table trên web app sử dụng Data Table jQuery plug-in.

2. Chức năng Search

Data Tables jQuery plug-in cũng có chức năng search build-in. Tuy nhiên, để search thì cần phải fetch toàn bộ data giống như phần 1 ở trên. Trong nhiều trường hợp, chúng ta không muốn công khai toàn bộ dữ liệu mà chỉ muốn người dùng search tìm đúng thông tin của họ. Chẳng hạn:

  • Tra cứu tình trạng đơn hàng bằng mã vận đơn.
  • Tra cứu hóa đơn bằng mã số hóa đơn.
  • Tra cứu lịch sử giao dịch bằng số tài khoản (hoặc số điện thoại).
  • Tra cứu thông tin nhân sự bằng mã nhân viên.

Chúng ta sẽ viết lại web và chỉ hiển thị thông tin theo dữ liệu mà người dùng search.

Search.html

File HTML này tương tự ở trên, chỉ có thêm thẻ <input> để người dùng nhập nội dung cần tìm.

<!-- File Search.html -->
<body> <div class="heading"> <h1>Search your invoice.</h1> <p>Input your phone number to search your invoice. Don't include country code, space and other special character.</p> </div> <div class="search-box"> <input id="searchText" type="text"> <button id="searchBtn" onclick="handleSearch()">Search</button> </div> <div class="response" id="status-box"> <table id="result" class="display" width="75%"></table> </div>
</body>

JavaScript.html

Khi người dùng nhấn button Search sau khi đã input dữ liệu thì client-side sẽ dùng class google.script.run để thực thi hàm searchByPhone(input) ở file code Apps Script. Sau khi return thì thêm dữ liệu vào Data Tables instance đã khởi tạo.

<script> function handleSearch() { // remove data in the previous search if ($.fn.DataTable.isDataTable('#result')) { $('#result').DataTable().clear().draw(); } $('#searchBtn').attr('disabled', true); // get value let input = document.getElementById('searchText').value; // validation // request server-side google.script.run .withSuccessHandler(onSuccess) .withFailureHandler(onFailure) .searchByPhone(input); // render response see function onSuccess() }; function onSuccess(result) { if ($.fn.DataTable.isDataTable('#result')) { appendDataTable('#result', result.data); } else { renderTable('#result', result); } $('#searchBtn').removeAttr('disabled'); }; function appendDataTable(elementSelector, rowData) { $(elementSelector).DataTable().rows.add(rowData).draw(); } function renderTable(elementSelector, option) { var table = $(elementSelector); var field = []; option.header.forEach(name => { field.push({title: name}); }); table.DataTable({ data: option.data, columns: field, paging: false, ordering: true, info: false, searching: false }); } function onFailure() { window.alert('Đã xảy ra lỗi khi truy cập file.') }
</script>

Route

Web app của chúng ta giờ đã có 2 trang nên viết lại hàm doGet(e) để thêm tham số p.

function doGet(e) { var page = e.parameter.p || 'Index'; return HtmlService.createTemplateFromFile(page) .evaluate();
} function searchByPhone(input) { var range = sheet.getDataRange(); var data = range.getValues(); var header = data[0]; var phoneCol = header.indexOf('Phone'); var result = data.filter(function(row) { return row[phoneCol] === input }); return { header: getHeaderArr(), data: result };
}

Như vậy, chúng ta đã xây dựng được chức năng search cơ bản để hiển thị dữ liệu lên web app Apps Script từ Google Sheets. Để hoàn thiện chức năng search này thì bạn có thể thực hiện validate search text và thêm loader để báo hiệu trạng thái load dữ liệu cho người dùng biết (giống phần 1), cũng như xử lý lỗi trong một số tình huống như không tìm thấy dữ liệu, người dùng chỉnh sửa tham số p nên không tìm thấy file.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Closure trong Javascript - Phần 2: Định nghĩa và cách dùng

Các bạn có thể đọc qua phần 1 ở đây. Để mọi người không quên, mình xin tóm tắt gọn lại khái niệm lexical environment:.

0 0 51

- vừa được xem lúc

Var vs let vs const? Các cách khai báo biến và hằng trong Javascript

Dạo này mình tập tành học Javascript, thấy có 2 cách khai báo biến khác nhau nên đã tìm tòi sự khác biệt. Nay xin đăng lên đây để mọi người đọc xong hy vọng phân biệt được giữa let và var, và sau đó là khai báo hằng bằng const.

0 0 31

- vừa được xem lúc

VueJS: Tính năng Mixins

Chào mọi người, hôm nay mình sẽ viết về Mixins và 1 số vấn đề trong sử dụng Mixins hay ho mà mình gặp trong dự án thực. Trích dẫn từ trang chủ của VueJS:.

0 0 27

- vừa được xem lúc

Asset Pipeline là cái chi chi?

Asset Pipeline. Asset pipeline là cái chi chi. . Giải thích:.

0 0 47

- vừa được xem lúc

Học Deep Learning trên Coursera miễn phí

Bạn muốn bắt đầu với Deep Learning nhưng không biết bắt đầu từ đâu? Bạn muốn có một công việc ở mức fresher về Deep Learning? Bạn muốn khoe bạn bè về kiến thức Deep Learning của mình. Bắt đầu từ đâu.

0 0 35

- vừa được xem lúc

Countdown timer và những cú lừa ?

Work from home nên mình chăm shopping online hơn hẳn. Hôm trước mình có canh flash sale trên một trang web nọ.

0 0 32