My google appscript code is experiencing issues. The search function in the back end is successfully outputting “results” but the front end “displayFunction” is not recieving the “results”. This results in the search page not working correctly.
I have tried logging the values. The search function in the backend output the data as an array correctly. Meanwhile, the function in the front end is not getting the correct value.
Front end code
<!DOCTYPE html>
<html>
<head>
<title>Search From Google Sheets</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
text-align: center;
background-color: #f7f7f7;
}
.search-container {
margin-top: 30px;
}
input[type="text"] {
padding: 10px;
width: 300px;
font-size: 16px;
margin-bottom: 20px;
}
button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
.results {
margin-top: 30px;
text-align: left;
display: inline-block;
width: 100%;
}
.result-item {
padding: 10px;
margin: 5px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
}
/* Styling for the "Add New Contact" button */
.add-contact-btn {
margin-top: 20px;
padding: 10px 20px;
background-color: #4CAF50;
color: white;
font-size: 16px;
cursor: pointer;
border: none;
border-radius: 5px;
}
/* Collapsible details */
.collapsible {
display: none;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 20px;
background-color: #f9f9f9;
border-top: 1px solid #ddd;
}
.collapsible-content {
margin-left: 20px;
}
</style>
</head>
<body>
<!-- Add New Contact button placed before the search bar -->
<button class="add-contact-btn" onclick="redirectToAddContactPage()">Add New Contact</button>
<div class="search-container">
<h1>Search Contacts</h1>
<!-- Input for real-time search -->
<input type="text" id="search-query" placeholder="Search for a name..." oninput="handleSearch(event)" />
</div>
<div class="results" id="search-results"></div>
<script>
// Handle real-time search functionality
function handleSearch(event) {
const query = event.target.value;
google.script.run.withSuccessHandler(displayResults).search(query);
}
// Display the search results returned from Apps Script
function displayResults(results) {
console.log("results are", results);
// Ensure results is an array before proceeding
if (!Array.isArray(results)) {
results = []; // If results is not an array, treat it as an empty array
}
const resultsDiv = document.getElementById('search-results');
resultsDiv.innerHTML = ''; // Clear previous results
if (results.length > 0) {
results.forEach(result => {
const resultItem = document.createElement('div');
resultItem.classList.add('result-item');
// Helper function to handle empty or missing values
const getDisplayValue = value => value ? value : 'N/A';
// Helper function to format Date objects
const formatDate = date => {
if (date instanceof Date && !isNaN(date)) {
return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`;
}
return 'N/A';
};
// Use helper functions for display
resultItem.innerHTML = `
<strong>ID Bệnh Nhân:</strong> ${getDisplayValue(result.id_benh_nhan)} <br>
<strong>Họ và Tên:</strong> ${getDisplayValue(result.name)} <br>
<button onclick="toggleDetails(event)">Show Details</button>
<div class="collapsible">
<div class="collapsible-content">
<strong>ID Gia Đình:</strong> ${getDisplayValue(result.id_gia_dinh)}<br>
<button onclick="toggleFamilyDetails(event, '${getDisplayValue(result.id_gia_dinh)}')">Show Family Details</button>
<div class="collapsible" id="family-details-${getDisplayValue(result.id_gia_dinh)}">
<!-- Family details will be injected here -->
</div><br>
<strong>ID Chế Độ Chính Sách:</strong> ${getDisplayValue(result.id_che_do_chinh_sach)}<br>
<strong>ID Lớp Học:</strong> ${getDisplayValue(result.id_lop_hoc)}<br>
<strong>ID Các Hỗ Trợ Của Làng:</strong> ${getDisplayValue(result.id_cac_ho_tro_cua_lang)}<br>
<strong>ID Bệnh Án:</strong> ${getDisplayValue(result.id_benh_an)}<br>
<strong>ID Đánh Giá:</strong> ${getDisplayValue(result.id_danh_gia)}<br>
<strong>Ngày Sinh:</strong> ${formatDate(new Date(result.ngay_sinh))}<br>
<strong>Giới Tính:</strong> ${getDisplayValue(result.gioi_tinh)}<br>
<strong>Địa Chỉ Gia Đình:</strong> ${getDisplayValue(result.dia_chi_gia_dinh)}<br>
<strong>Số Định Danh Cá Nhân:</strong> ${getDisplayValue(result.so_dinh_danh_ca_nhan)}<br>
<strong>Đối Tượng, Thế Hệ Thứ:</strong> ${getDisplayValue(result.doi_tuong_the_he_thu)}<br>
<strong>Hộ Khẩu:</strong> ${getDisplayValue(result.ho_khau)}<br>
<strong>Ngày Tiếp Nhận:</strong> ${formatDate(new Date(result.ngay_tiep_nhan))}<br>
<strong>Ngày Hòa Nhập:</strong> ${formatDate(new Date(result.ngay_hoa_nhap))}<br>
</div>
</div>
`;
resultsDiv.appendChild(resultItem);
});
} else {
resultsDiv.innerHTML = '<p>No results found.</p>';
}
}
// Toggle the display of the detailed contact information
function toggleDetails(event) {
const collapsible = event.target.nextElementSibling;
if (collapsible.style.display === 'none' || collapsible.style.display === '') {
collapsible.style.display = 'block';
event.target.textContent = 'Hide Details';
} else {
collapsible.style.display = 'none';
event.target.textContent = 'Show Details';
}
}
// Toggle family details section based on ID Gia Đình
function toggleFamilyDetails(event, idGiaDinh) {
const familyDetailsDiv = document.getElementById(`family-details-${idGiaDinh}`);
if (familyDetailsDiv.style.display === 'none' || familyDetailsDiv.style.display === '') {
google.script.run.withSuccessHandler(function(familyDetails) {
familyDetailsDiv.innerHTML = `
<strong>Họ và Tên Bố:</strong> ${familyDetails.father_name}<br>
<strong>Họ và Tên Mẹ:</strong> ${familyDetails.mother_name}<br>
<strong>SĐT Liên Hệ:</strong> ${familyDetails.contact_number}<br>
<strong>Nghề Nghiệp Bố:</strong> ${familyDetails.father_occupation}<br>
<strong>Nghề Nghiệp Mẹ:</strong> ${familyDetails.mother_occupation}<br>
<strong>Địa Chỉ:</strong> ${familyDetails.address}<br>
<strong>Thông Tin Người Giám Hộ:</strong> ${familyDetails.guardian_info}<br>
`;
familyDetailsDiv.style.display = 'block';
event.target.textContent = 'Hide Family Details';
}).getFamilyDetails(idGiaDinh);
} else {
familyDetailsDiv.style.display = 'none';
event.target.textContent = 'Show Family Details';
}
}
// Redirects the user to the "Add/Edit Contact" page
function redirectToAddContactPage() {
google.script.run.withSuccessHandler(function(html) {
document.open();
document.write(html);
document.close();
}).getedit_contacts();
}
// Initial load of all contacts when the page loads
window.onload = function() {
loadAllContacts();
};
function loadAllContacts() {
google.script.run.withSuccessHandler(displayResults).getAllContacts();
}
</script>
</body>
</html>
Backend code
// This function fetches all contacts, including additional fields
function getAllContacts() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Bệnh nhân'); // Ensure correct sheet name
const data = sheet.getDataRange().getValues(); // Get all data from the sheet (including headers)
const contacts = [];
// Loop through all rows (skipping the header row)
for (let i = 1; i < data.length; i++) {
const contact = {
id_benh_nhan: data[i][0] || 'N/A', // ID bệnh nhân (use 'N/A' if empty)
id_gia_dinh: data[i][1] || 'N/A', // ID gia đình
id_che_do_chinh_sach: data[i][2] || 'N/A', // ID chế độ chính sách
id_lop_hoc: data[i][3] || 'N/A', // ID lớp học
id_cac_ho_tro_cua_lang: data[i][4] || 'N/A', // ID các hỗ trợ của làng
id_benh_an: data[i][5] || 'N/A', // ID bệnh án
id_danh_gia: data[i][6] || 'N/A', // ID đánh giá
name: data[i][7] || 'N/A', // Họ và tên
ngay_sinh: data[i][8] || 'N/A', // Ngày sinh
gioi_tinh: data[i][9] || 'N/A', // Giới tính
dia_chi_gia_dinh: data[i][10] || 'N/A', // Địa chỉ gia đình
so_dinh_danh_ca_nhan: data[i][11] || 'N/A', // Số định danh cá nhân
doi_tuong_the_he_thu: data[i][12] || 'N/A', // Đối tượng, thế hệ thứ
ho_khau: data[i][13] || 'N/A', // Hộ khẩu
ngay_tiep_nhan: data[i][14] || 'N/A', // Ngày tiếp nhận
ngay_hoa_nhap: data[i][15] || 'N/A' // Ngày hòa nhập
};
contacts.push(contact);
}
// Return all contacts
return contacts;
}
// This function performs the search operation
function search(query) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Bệnh nhân'); // Change 'Bệnh nhân' to your actual sheet name
const data = sheet.getDataRange().getValues(); // Get all data from the sheet (including headers)
const results = [];
// Ensure query is a string and convert to lowercase for case-insensitive comparison
const searchQuery = (query && query.toString().toLowerCase()) || ''; // Handle query if undefined or null
// Loop through the rows in the sheet starting from the second row (skipping the header row)
for (let i = 1; i < data.length; i++) {
// Ensure the name field (data[i][7]) exists and is a string before calling .toString()
const name = (data[i][7] && data[i][7].toString().toLowerCase()) || ''; // If name is undefined or null, use an empty string
// If the name contains the search query (case-insensitive), add the result to the 'results' array
if (name.includes(searchQuery)) {
const result = {
id_benh_nhan: data[i][0],
id_gia_dinh: data[i][1],
id_che_do_chinh_sach: data[i][2],
id_lop_hoc: data[i][3],
id_cac_ho_tro_cua_lang: data[i][4],
id_benh_an: data[i][5],
id_danh_gia: data[i][6],
name: data[i][7],
ngay_sinh: data[i][8],
gioi_tinh: data[i][9],
dia_chi_gia_dinh: data[i][10],
so_dinh_danh_ca_nhan: data[i][11],
doi_tuong_the_he_thu: data[i][12],
ho_khau: data[i][13],
ngay_tiep_nhan: data[i][14],
ngay_hoa_nhap: data[i][15]
};
results.push(result); // Add the matching result
}
}
// Return the results array to the front-end (HTML page)
Logger.log(results);
return results;
}
// This function fetches the family details for a given ID Gia Đình
function getFamilyDetails(idGiaDinh) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Gia đình'); // Ensure correct sheet name
const data = sheet.getDataRange().getValues(); // Get all data from the sheet (including headers)
let familyDetails = {
father_name: 'N/A', // Default values in case data is missing
mother_name: 'N/A',
contact_number: 'N/A',
father_occupation: 'N/A',
mother_occupation: 'N/A',
address: 'N/A',
guardian_info: 'N/A'
};
// Loop through the rows in the "Gia Đình" sheet and find the matching ID Gia Đình
for (let i = 1; i < data.length; i++) {
const familyId = data[i][0]; // Assuming ID Gia Đình is in the first column
if (familyId == idGiaDinh) {
familyDetails = {
father_name: data[i][1] || 'N/A', // Họ và tên bố
mother_name: data[i][2] || 'N/A', // Họ và tên mẹ
contact_number: data[i][3] || 'N/A', // SĐT liên hệ
father_occupation: data[i][4] || 'N/A', // Nghề nghiệp bố
mother_occupation: data[i][5] || 'N/A', // Nghề nghiệp mẹ
address: data[i][6] || 'N/A', // Địa chỉ
guardian_info: data[i][7] || 'N/A' // Thông tin người giám hộ
};
break;
}
}
return familyDetails;
}