Google Spread Sheet Search any part of the cell and display - google-apps-script

I have a code to search and display the exact field in any column.
I would like to get the code of partial search, such that the input value if we entre is partial, should display all the possible fields.
Eg. Search "Evaluation" in the search field should display all the possible results.
enter image description here
function doGet() {
return HtmlService.createTemplateFromFile('Index').evaluate();
}
/* PROCESS FORM */
function processForm(formObject){
var result = "";
if(formObject.searchtext){//Execute if form passes search text
result = search(formObject.searchtext);
}
return result;
}
//SEARCH FOR MATCHED CONTENTS
function search(searchtext){
var spreadsheetId = '1iG30kufq5MQpd0xmoPhPir5iA3hlz8s7vI_0EWQfg7Q'; //** CHANGE !!!
var dataRage = 'Data!A2:Y'; //** CHANGE !!!
var data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRage).values;
var ar = [];
data.forEach(function(f) {
if (~f.indexOf(searchtext)) {
ar.push(f);
}
});
return ar;
}
HTML CODE
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js" integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o" crossorigin="anonymous"></script>
<!--##JAVASCRIPT FUNCTIONS ---------------------------------------------------- -->
<script>
//PREVENT FORMS FROM SUBMITTING / PREVENT DEFAULT BEHAVIOUR
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener("load", preventFormSubmit, true);
//HANDLE FORM SUBMISSION
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(createTable).processForm(formObject);
document.getElementById("search-form").reset();
}
//CREATE THE DATA TABLE
function createTable(dataArray) {
if(dataArray && dataArray !== undefined && dataArray.length != 0){
var result = "<table class='table table-sm table-striped' id='dtable' style='font-size:0.8em'>"+
"<thead style='white-space: nowrap'>"+
"<tr>"+ //Change table headings to match witht he Google Sheet
"<th scope='col'>MS No</th>"+
"<th scope='col'>Title</th>"+
"<th scope='col'>Status</th>"+
"<th scope='col'>Date</th>"+
"</tr>"+
"</thead>";
for(var i=0; i<dataArray.length; i++) {
result += "<tr>";
for(var j=0; j<dataArray[i].length; j++){
result += "<td>"+dataArray[i][j]+"</td>";
}
result += "</tr>";
}
result += "</table>";
var div = document.getElementById('search-results');
div.innerHTML = result;
}else{
var div = document.getElementById('search-results');
//div.empty()
div.innerHTML = "Data not found!";
}
}
</script>
<!--##JAVASCRIPT FUNCTIONS ~ END ---------------------------------------------------- -->
</head>
<body>
<div class="container">
<br>
<div class="row">
<div class="col">
<!-- ## SEARCH FORM ------------------------------------------------ -->
<form id="search-form" class="form-inline" onsubmit="handleFormSubmit(this)">
<div class="form-group mb-2">
<label for="searchtext">Search MS No</label>
</div>
<div class="form-group mx-sm-3 mb-2">
<input type="text" class="form-control" id="searchtext" name="searchtext" placeholder="Enter MS No">
</div>
<button type="submit" class="btn btn-primary mb-2">Search</button>
</form>
<!-- ## SEARCH FORM ~ END ------------------------------------------- -->
</div>
</div>
<div class="row">
<div class="col">
<!-- ## TABLE OF SEARCH RESULTS ------------------------------------------------ -->
<div id="search-results" class="table-responsive">
<!-- The Data Table is inserted here by JavaScript -->
</div>
<!-- ## TABLE OF SEARCH RESULTS ~ END ------------------------------------------------ -->
</div>
</div>
</div>
<div class="container">
<br>
<div class="row">
<div class="col">
<!-- ## SEARCH FORM ------------------------------------------------ -->
<form id="search-form" class="form-inline" onsubmit="handleFormSubmit(this)">
<div class="form-group mb-2">
<label for="searchtext">Search Title</label>
</div>
<div class="form-group mx-sm-3 mb-2">
<input type="text" class="form-control" id="searchtext" name="searchtext" placeholder="Enter Title">
</div>
<button type="submit" class="btn btn-primary mb-2">Search</button>
</form>
<!-- ## SEARCH FORM ~ END ------------------------------------------- -->
</div>
</div>
<div class="row">
<div class="col">
<!-- ## TABLE OF SEARCH RESULTS ------------------------------------------------ -->
<div id="search-results" class="table-responsive">
<!-- The Data Table is inserted here by JavaScript -->
</div>
<!-- ## TABLE OF SEARCH RESULTS ~ END ------------------------------------------------ -->
</div>
</div>
</div>
</body>
</html>

This will highlight partial substring matches in red:
function searchhilight() {
let hilite = SpreadsheetApp.newTextStyle().setBold(true).setForegroundColor('red').build();
let normal = SpreadsheetApp.newTextStyle().setBold(false).setForegroundColor('black').build();
const ui = SpreadsheetApp.getUi();
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const sr = 2;//data start row
const rg = sh.getRange(sr, 1, sh.getLastRow() - sr + 1, sh.getLastColumn());
rg.setFontColor('black').setFontWeight('normal');//set all data to black text with no bold
const dvs = rg.getDisplayValues();
const resp = ui.prompt('Search Text', 'Enter Search String', ui.ButtonSet.OK_CANCEL);
if (resp.getSelectedButton() == ui.Button.OK) {
const st = resp.getResponseText();
dvs.forEach((r, i) => {
r.forEach((c, j) => {
let idx = '';
fidx = '';//from index
iA = [];//index array of matches
do {
idx = c.indexOf(st, fidx);
if (~idx) {
fidx = idx + st.length;
iA.push({ idxs: idx, idxe: idx + st.length })
}
} while (~idx);
let rtv = SpreadsheetApp.newRichTextValue().setText(c);
iA.forEach(obj => rtv.setTextStyle(obj.idxs, obj.idxe, hilite));
sh.getRange(i + sr, j + 1).setNumberFormat('#STRING#');
sh.getRange(i + sr, j + 1).setRichTextValue(rtv.build());
});
});
}
}
This function will also reformat every cell in the data range to plain text.
RichTextValueBuilder
RichTextValue

function search(searchtext){
var spreadsheetId = '1do6G8pScBAz0Z7GOCjbBcXPKJkhbOwlSx5BZyt6S7H8'; //** CHANGE !!!
var dataRage = 'Data!A2:Y'; //** CHANGE !!!
var data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRage).values;
var ar = [];
data.forEach(function(f) {
if (~f.toString().toLowerCase().indexOf(searchtext.toString().toLowerCase())) {
ar.push(f);
}
});
return ar;
}

Related

How to fill a multiple string to filter a data in Google Apps Script

I'm going to build web to be used in search for label information
My database is in Google Sheets, so I went looking for a Google Sheets fetch and gave it a try. I have no experience with Google App Scripts so I want to fill all and search data form database but it can run just one of them how to do it all (first is .gs second is Index.html) this is my reference.
https://gist.github.com/neno-tech/15d9c3fe32a2d8896c1875b7a827a6e5
https://docs.google.com/document/d/1EhzxSy-L5kBt5E-BA1B446G0OjQAuKqEgLUPpiZh3Pw/edit
This is my database : https://docs.google.com/spreadsheets/d/1j-r4gD1zV3e0yrNJTnHezXRlv1w-aOf6UqQs_P2jsRY/edit?usp=sharing
function doGet() {
return HtmlService.createTemplateFromFile('Index').evaluate()
.setTitle('System Search Lable')
.addMetaTag('viewport', 'width=device-width, inital-scale=1')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
function processForm(formObject){
var concat = formObject.searchtext+formObject.searchtext2+formObject.searchtext3+formObject.searchtext4+formObject.searchtext5;
var result = "";
if(concat){
result = search(concat);
}
return result;
}
function search(searchtext){
var spreadsheetId = '1j-r4gD1zV3e0yrNJTnHezXRlv1w-aOf6UqQs_P2jsRY';
var dataRange = 'Master Barcode!A2:O10';
var data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRange).values;
var ar = [];
data.forEach(function(f) {
if (~f.toString().toLowerCase().indexOf(searchtext.toString().toLowerCase())) {
ar.push(f);
}
});
return ar;
}
!DOCTYPE html>
<html>
<head>
<base target="_top">
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
</head>
<body>
<div class="container">
<br>
<div class="row">
<div class="col">
<center><form id="search-form" onsubmit="handleFormSubmit(this)">
<div class="form-group mb-2">
<label for="searchtext">Search a Label</label>
</div><p>
<div class="col-md-6 mb-2">
<input type="text" class="form-control" id="searchtext" name="searchtext" placeholder="Category">
<br>
<input type="text" class="form-control" id="searchtext2" name="searchtext2" placeholder="Size">
<br>
<input type="text" class="form-control" id="searchtext3" name="searchtext3" placeholder="Brand">
<br>
<input type="text" class="form-control" id="searchtext4" name="searchtext4" placeholder="Color">
<br>
<input type="text" class="form-control" id="searchtext5" name="searchtext5" placeholder="Lenght">
<br>
</div><p>
<button id="search" type="submit" class="btn btn-success mb-2">Search</button>
<span id="spinner" class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
</form>
</center>
</div>
</div>
<div class="row">
<div class="col">
<div id="search-results" class="table-responsive">
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/#popperjs/core#2.5.4/dist/umd/popper.min.js" integrity="sha384-q2kxQ16AaE6UbzuKqyBE9/u/KzioAlnx2maXQHiDX9d4/zp8Ok3f+M7DPm+Ib6IU" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta1/dist/js/bootstrap.min.js" integrity="sha384-pQQkAEnwaBkjpqZ8RU1fF1AKtTcHJwFl3pblpTlHXybJjHpMYo79HY3hIi4NKxyj" crossorigin="anonymous"></script>
<script>
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener("load", preventFormSubmit, true);
function handleFormSubmit(formObject) {
document.getElementById('search').innerHTML = "Loading";
document.getElementById('spinner').classList.remove("d-none");
google.script.run.withSuccessHandler(createTable).processForm(formObject);
document.getElementById("search-form").reset();
}
function createTable(dataArray) {
document.getElementById('search').innerHTML = "Search";
document.getElementById('spinner').classList.add("d-none");
if(dataArray && dataArray !== undefined && dataArray.length != 0){
var result = "<table class='table table-sm table-striped' id='dtable' style='font-size:0.8em'>"+
"<thead style='white-space: nowrap'>"+
"<tr>"+
"<th scope='col'>Barcode</th>"+
"<th scope='col'>Brand</th>"+
"<th scope='col'>Standard</th>"+
"<th scope='col'>Year</th>"+
"<th scope='col'>Table</th>"+
"<th scope='col'>Type</th>"+
"<th scope='col'>Category</th>"+
"<th scope='col'>Coil</th>"+
"<th scope='col'>X</th>"+
"<th scope='col'>Size</th>"+
"<th scope='col'>Lenght</th>"+
"<th scope='col'>Weight</th>"+
"<th scope='col'>Color</th>"+
"<th scope='col'>Voltage</th>"+
"<th scope='col'>Size lable</th>"+
"</tr>"+
"</thead>";
for(var i=0; i<dataArray.length; i++) {
result += "<tr>";
for(var j=0; j<dataArray[i].length; j++){
result += "<td>"+dataArray[i][j]+"</td>";
}
result += "</tr>";
}
result += "</table>";
var div = document.getElementById('search-results');
div.innerHTML = result;
}else{
var div = document.getElementById('search-results');
div.innerHTML = "Data not found!";
}
}
</script>
</body>
</html>
The results are here is that I fill in only one field. What I mean is I filled out the required information into each field, however I would like to know a way to fill in all fields in order to make it easier to filter.
To filter results based on the values you enter in the web form, pass all search elements to your search function and then check that that they are all either blank or match. This assumes that the search terms and the columns in your sheet are in the same order. Example:
const MAPPING = [7, 10, 2, 13, 11];
function processForm({ searchtext, searchtext2, searchtext3, searchtext4, searchtext5 }){
let searchTerms = [searchtext, searchtext2, searchtext3, searchtext4, searchtext5];
var result = "";
if(searchTerms.find(Boolean)){
result = search(searchTerms);
}
return result;
}
function search(searchTerms){
var spreadsheetId = '1B0hcELJcoLxiYXNCDx9iRl8JxijwgdFBkte90oPfCnY';
var dataRange = 'Master Barcode!A46:O1346';
var data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRange).values;
var ar = [];
data.forEach(function(f) {
if (searchTerms.every((e, i) => !e || e === f[MAPPING[i]-1])) {
ar.push(f);
}
});
return ar;
}

How to add options to an HTML Table using Apps Script?

I was wondering how I could add these options to an HTML table within Apps Script Editor.
Here's the script:
function doGet() {
return HtmlService.createTemplateFromFile('Index').evaluate();
}
/* PROCESS FORM */
function processForm(formObject) {
var result = "";
if (formObject.searchtext) {//Execute if form passes search text
result = search(formObject.searchtext);
}
return result;
}
//SEARCH FOR MATCHED CONTENTS
function search(searchtext) {
//const searchtext = 'test#email.com'
const ss = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheetId = ss.getId();
var dataRage = 'Approval Tracker!A2:J';
var data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRage).values;
var ar = [];
data.forEach(function (f) {
if (f[9] == searchtext) {
ar.push([f[3], f[4], f[5], f[6], f[2]]);
}
});
return ar;
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous">
</script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"
integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o" crossorigin="anonymous">
</script>
<!--##JAVASCRIPT FUNCTIONS ---------------------------------------------------- -->
<script>
//PREVENT FORMS FROM SUBMITTING / PREVENT DEFAULT BEHAVIOUR
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener("load", preventFormSubmit, true);
//HANDLE FORM SUBMISSION
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(createTable).processForm(formObject);
//document.getElementById("search-form").reset();
}
//CREATE THE DATA TABLE
function createTable(dataArray) {
if(dataArray && dataArray !== undefined && dataArray.length != 0){
var result = "<table class='table table-sm table-striped' id='dtable' style='font-size:0.8em'>"+
"<thead style='white-space: nowrap'>"+
"<tr>"+ //Change table headings to match witht he Google Sheet
"<th scope='col'>Date Assigned</th>"+
"<th scope='col'>Item</th>"+
"<th scope='col'>Link To File</th>"+
"<th scope='col'>Notes</th>"+
"<th scope='col'>Approval Status</th>"+
"<td><select name='D1'>" +
"<option value='volvo'>Volvo</option>" +
"<option value='saab'>Saab</option>" +
"<option value='mercedes'>Mercedes</option>" +
"<option value='audi'>Audi</option>" +
"</select>"+
"</td>" +
"</tr>" +
"</thead>";
for(var i=0; i<dataArray.length; i++) {
result += "<tr>";
for(var j=0; j<dataArray[i].length; j++){
result += "<td>"+dataArray[i][j]+"</td>";
}
result += "</tr>";
}
result += "</table>";
var div = document.getElementById('search-results');
div.innerHTML = result;
}else{
var div = document.getElementById('search-results');
//div.empty()
div.innerHTML = "Data not found!";
}
}
</script>
<!--##JAVASCRIPT FUNCTIONS ~ END ---------------------------------------------------- -->
</head>
<body>
<div class="container">
<br>
<div class="row">
<div class="col">
<!-- ## SEARCH FORM ------------------------------------------------ -->
<form id="search-form" class="form-inline" onsubmit="handleFormSubmit(this)">
<div class="form-group mb-2">
<label for="searchtext">Enter your email</label>
</div>
<div class="form-group mx-sm-3 mb-2">
<input type="text" class="form-control" id="searchtext" name="searchtext" placeholder="Enter your email">
</div>
<button type="submit" class="btn btn-primary mb-2">Search</button>
</form>
<!-- ## SEARCH FORM ~ END ------------------------------------------- -->
</div>
</div>
<div class="row">
<div class="col">
<!-- ## TABLE OF SEARCH RESULTS ------------------------------------------------ -->
<div id="search-results" class="table-responsive">
<!-- The Data Table is inserted here by JavaScript -->
</div>
<!-- ## TABLE OF SEARCH RESULTS ~ END ------------------------------------------------ -->
</div>
</div>
</div>
</body>
</html>
This is the file's link:
This is the Web App URL
It's now appending one koption list to the header.
Appreciate any help!
From I've tried it above but the page is empty., if your are using your showing script, I think that your script is incomplete. So, please modify as follows and test it again.
From:
"<option value='audi'>Audi</option>" +
"</select></td>
"</tr>" +
"</thead>";
To:
"<option value='audi'>Audi</option>" +
"</select></td></tr></thead>";

Google Web App - Search box to filter the data from Google Spread sheet

Thanks in advance. Just to start with, I am not a coder, but I keep on researching. I made a search Web App to filter the data from Google spreadsheet which has more than 2000+ rows, which keeps on increasing day by day and around 135 columns for different Institutes. So, it was messy to search in that Google sheet, and hence I created this web app.
Everything is working smoothly until the records were around 1200 rows but now I am facing an issue to display more than 2000 records. The Web App Search box displays the list based on the key we pressed. Like if we enter "A", it will display the names starting from the alphabet "A". So, what I do is, I keep on adding the new tags (Institute names) and it works well but now suddenly after adding few records, it says unable to open the file.
Request you to please look into this and let me know any alternative or correct this code to work smoothly regardless of the numbers of tags or rows. Thank you so much.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js" integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o" crossorigin="anonymous"></script>
<!-- <link href="path/to/select2.min.css" rel="stylesheet" />
<script src="path/to/select2.min.js"></script> -->
<!-- <link href="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/js/select2.min.js"></script> -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Autocomplete using Jquery</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.
css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<!--##JAVASCRIPT FUNCTIONS ---------------------------------------------------- -->
<script type="text/javascript">
$( function() {
var searchtext = [
"Australian Catholic University",
"Australian National University (ANU)",
"Central Queensland University",
"Royal Melbourne Institute of Technology (RMIT)",
/*Like this we have more that 2000 names of Institutes*/
];
$( "#searchtext" ).autocomplete({
source: searchtext
/* #the tags is the id of the input element
source: tags is the list of available tags*/
});
} );
//PREVENT FORMS FROM SUBMITTING / PREVENT DEFAULT BEHAVIOUR
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener("load", preventFormSubmit, true);
// $(document).ready(function() {
// $('.js-example-basic-single').select2();
// });
function myFunction() {
document.getElementById("searchtext").size = "70";
}
//HANDLE FORM SUBMISSION
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(createTable).processForm(formObject);
// document.getElementById("search-form").reset();
}
//CREATE THE DATA TABLE
function createTable(dataArray) {
if(dataArray && dataArray !== undefined && dataArray.length != 0){
var result = "<table class='table table-sm table-striped' id='dtable' style='font-size:0.8em'>"+
"<thead style='white-space: nowrap'>"+
"<tr>"+ //Table headings
"<th scope='col'>Institution</th>"+
"<th scope='col'>Agreement with</th>"+
"<th scope='col'>Type of institution</th>"+
"<th scope='col'>Country</th>"+
/*Around 100+ Columns are there*/
"</thead>";
for(var i=0; i<dataArray.length; i++) {
result += "<tr>";
for(var j=0; j<dataArray[i].length; j++){
result += "<td>"+dataArray[i][j]+"</td>";
}
result += "</tr>";
}
result += "</table>";
var div = document.getElementById('search-results');
div.innerHTML = result;
}else{
var div = document.getElementById('search-results');
//div.empty()
div.innerHTML = "Data not found!";
}
}
</script>
<!--##JAVASCRIPT FUNCTIONS ~ END ---------------------------------------------------- -->
</head>
<body style="background-color:#cdffcd;">
<h1 align="center"><img src="https://drive.google.com/uc?export=download&id=16SqA92JMCD3AVWH07BeyPPLlEBaO_4Ae" alt="logo" width="120" height="100"/> The SoT Search Form</h1>
<div class="container">
<br>
<div class="row">
<div class="col">
<!-- ## SEARCH FORM ------------------------------------------------ -->
<form id="search-form" class="form-inline" onsubmit="handleFormSubmit(this)" action="/action_page.php" method="get">
<div class="form-group mb-2">
<label for="searchtext" align="center"><strong>Search for the provider</strong></label>
</div>
<div class="form-group mx-sm-3 mb-2">
<input id="searchtext" name="searchtext" class="form-control" onclick="myFunction()" placeholder="Enter the name.." align="center">
<!-- On keyup calls the function everytime a key is released -->
</div>
<button type="submit" class="btn btn-primary mb-2">Search</button>
<input type="reset" class="btn btn-primary mb-2" id="resetbutton" style='margin-left:16px' value="Reset">
</form>
<!-- ## SEARCH FORM ~ END ------------------------------------------- -->
</div>
</div>
<div class="row">
<div class="col">
<!-- ## TABLE OF SEARCH RESULTS ------------------------------------------------ -->
<div id="search-results" class="table-responsive">
<!-- The Data Table is inserted here by JavaScript -->
</div>
<!-- ## TABLE OF SEARCH RESULTS ~ END ------------------------------------------------ -->
</div>
</div>
</div>
</body>
</html>
============= Code File===========================================
function doGet() {
return HtmlService.createTemplateFromFile('Index').evaluate();
}
/* PROCESS FORM */
function processForm(formObject){
var result = "";
if(formObject.searchtext){//Execute if form passes search text
result = search(formObject.searchtext);
}
return result;
}
//SEARCH FOR MATCHED CONTENTS
function search(searchtext){
var spreadsheetId = 'xxxxxxx';
var dataRage = 'ABC!A2:DV1500';
var data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRage).values;
var ar = [];
data.forEach(function(f) {
if (~f.indexOf(searchtext)) {
ar.push(f);
}
});
return ar;
}

Google sheet + Web app search multiple google workbook and return all matching rows

Anybody knows how can I amend the code below to search from 2 separate google workbooks? Currently, this only works to search from 1 google sheet in 1 workbook.
Both these sheets have the exact same headers.
When the user searches for a specific text, it should display the matching rows from both workbooks.
Code.gs:
function doGet() {
return HtmlService.createTemplateFromFile('Index')
.evaluate()
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
/* PROCESS FORM */
function processForm(formObject){
var result = "";
if(formObject.searchtext){//Execute if form passes search text
result = search(formObject.searchtext);
}
return result;
}
//SEARCH FOR MATCHED CONTENTS
function search(searchtext){
var spreadsheetId = '1443X5UzzRfpYachZZLFrmYFq821ioioqwFAnASY'; //** CHANGE !!!
var dataRage = 'TEST!A2:F'; //** CHANGE !!!
var data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRage).values;
var ar = [];
data.forEach(function(f) {
if (~f.indexOf(searchtext)) {
ar.push(f);
}
});
return ar;
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js" integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o" crossorigin="anonymous"></script>
<!--##JAVASCRIPT FUNCTIONS ---------------------------------------------------- -->
<script>
//PREVENT FORMS FROM SUBMITTING / PREVENT DEFAULT BEHAVIOUR
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener("load", preventFormSubmit, true);
//HANDLE FORM SUBMISSION
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(createTable).processForm(formObject);
document.getElementById("search-form").reset();
}
//CREATE THE DATA TABLE
function createTable(dataArray) {
if(dataArray && dataArray !== undefined && dataArray.length != 0){
var result = "<table class='table table-sm table-striped' id='dtable' style='font-size:0.8em'>"+
"<thead style='white-space: nowrap'>"+
"<tr>"+ //Change table headings to match witht he Google Sheet
"<th scope='col'>Group</th>"+
"<th scope='col'>QO Number</th>"+
"<th scope='col'>Patient NRIC</th>"+
"<th scope='col'>Swab Date</th>"+
"<th scope='col'>Lab ID</th>"+
"<th scope='col'>SERO Lab ID</th>"+
"</tr>"+
"</thead>";
for(var i=0; i<dataArray.length; i++) {
result += "<tr>";
for(var j=0; j<dataArray[i].length; j++){
result += "<td>"+dataArray[i][j]+"</td>";
}
result += "</tr>";
}
result += "</table>";
var div = document.getElementById('search-results');
div.innerHTML = result;
}else{
var div = document.getElementById('search-results');
//div.empty()
div.innerHTML = "Data not found!";
}
}
</script>
<!--##JAVASCRIPT FUNCTIONS ~ END ---------------------------------------------------- -->
</head>
<body>
<div class="container">
<br>
<div class="row">
<div class="col">
<!-- ## SEARCH FORM ------------------------------------------------ -->
<form id="search-form" class="form-inline" onsubmit="handleFormSubmit(this)">
<div class="form-group mb-2">
<label for="searchtext">Swab Search</label>
</div>
<div class="form-group mx-sm-3 mb-2">
<input type="text" class="form-control" id="searchtext" name="searchtext" placeholder="QO or NRIC (last 4 digits)">
</div>
<button type="submit" class="btn btn-primary mb-2">Search</button>
</form>
<!-- ## SEARCH FORM ~ END ------------------------------------------- -->
</div>
</div>
<div class="row">
<div class="col">
<!-- ## TABLE OF SEARCH RESULTS ------------------------------------------------ -->
<div id="search-results" class="table-responsive">
<!-- The Data Table is inserted here by JavaScript -->
</div>
<!-- ## TABLE OF SEARCH RESULTS ~ END ------------------------------------------------ -->
</div>
</div>
</div>
</body>
</html>
Have an array with the ID of the different spreadsheets you want to retrieve data from, and iterate through that:
function search(searchtext){
var spreadsheetIds = ['1443X5UzzRfpYachZZLFrmYFq821ioioqwFAnASY'];
var dataRage = 'TEST!A2:F';
var ar = [];
spreadsheetIds.forEach(spreadsheetId => {
var data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRage).values;
data.forEach(function(f) {
if (~f.indexOf(searchtext)) {
ar.push(f);
}
});
});
return ar;
}
If the range notation of the different spreadsheets should also change, then have an array with those ranges too, and access each element in the array using the forEach index parameter:
function search(searchtext){
var spreadsheetIds = ['SPREADSHEET_ID_1', 'SPREADSHEET_ID_2'];
var dataRages = ['RANGE_1', 'RANGE_2'];
var ar = [];
spreadsheetIds.forEach((spreadsheetId, i) => {
var data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRages[i]).values;
data.forEach(function(f) {
if (~f.indexOf(searchtext)) {
ar.push(f);
}
});
});
return ar;
}
Not sure if you want to retrieve more information than just the row index, but if that's the case, just push that information to ar, not just f.
Alternatively, use reduce:
function search(searchtext) {
const spreadsheetIds = ['SPREADSHEET_ID_1', 'SPREADSHEET_ID_2'];
const dataRages = ['RANGE_1', 'RANGE_2'];
const ar = spreadsheetIds.reduce((acc, spreadsheetId, i) => {
const data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRages[i]).values;
return acc.concat(data.filter(f => f.includes(searchText)));
}, []);
return ar;
}
Reference:
Array.prototype.reduce()

Apps Script: Collect Form Input and Display Today's Total

First time poster here: I've created a web app in Apps Script where the user enters:
Date
Food
Quantity
...then the associated 'health points' are calculated and added to a spreadsheet in Google Sheets.
What I want to do is calculate and display the day's total and then recalculate and display whenever the form is submitted. I'm still a newer JS user, so I'm cheating a bit by calculating in Google Sheets. Here's what that formula looks like:
=sum(ArrayFormula(if(today()-1=Data!A:A,Data!B:B,0)))
..then I'm passing that as a template value. That works when loading the page, but I would like it to update whenever the form is submitted.
Do you have ideas on how to calculate today's total using a script instead of Sheets and recalculating/displaying when the form is submitted?
Update: I've attached the code. And here's the sheet: https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit?usp=sharing
function doGet(request) {
var t = HtmlService.createTemplateFromFile('index');
var url = "https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Points");
var total = ws.getRange(1,1,1,1).getValue();
var remaining = 25-total;
Logger.log(total);
Logger.log(remaining);
t.total = total;
t.remaining = remaining;
return t.evaluate();
}
function getLast() {
var url = "https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Data");
var last = ws.getLastRow();
Logger.log(last);
}
/* #Include JavaScript and CSS Files */
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
/* #Process Form */
function processForm(formObject) {
// (Calories * .0305) + (Sat Fat * .275) + (Sugar * .12) - (Protein * .098)
var smartpointsServing = Math.round((formObject.calories * .0305) + (formObject.satfat * .275) + (formObject.sugar * .12) - (formObject.protein * .098));
// var formattedDate = Utilities.formatDate(new Date(formObject.today), "GMT-6", "MM/dd/yyyy");
var url = "https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Foods");
var ws2 = ss.getSheetByName("Data");
var newFoodHp = smartpointsServing*formObject.quantity;
if (formObject.new_food_name !== ""){
ws.appendRow([formObject.new_food_name,
smartpointsServing,
formObject.serving_size_no,
formObject.serving_size_unit,
formObject.calories,
formObject.satfat,
formObject.sugar,
formObject.protein]);
ws2.appendRow([formObject.today,
newFoodHp,
formObject.food_name,
formObject.quantity]);}
else {
ws2.appendRow([formObject.today,
formObject.smartpoints,
formObject.food_name,
formObject.quantity]);
}
}
function getSmartPoints(foodLookup){
var url = "https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Foods");
var data = ws.getRange(2, 1, ws.getLastRow()-1, 2).getValues();
var foodList = data.map(function(r){ return r[0]; });
var smartpointsPerServing = data.map(function(r){ return r[1]; });
var position = foodList.indexOf(foodLookup);
if (position >-1){
return smartpointsPerServing[position];
} else {
return 'Food Not Found';
}
}
function returnDropDownArray() {
var url = "https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Foods");
var array = ws.getRange(2,1,ws.getLastRow()-1,1).getValues().sort();
Logger.log(array);
return ws.getRange(2,1,ws.getLastRow()-1,1).getValues().sort();
}
<!DOCTYPE html>
<html>
<head>
<!--Install Bootstrap-->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<?!= include('JavaScript'); ?>
<style>
body {
color: blue;
}
</style>
</head>
<body>
<p id="date"></p>
<div class="container">
<form id="myForm" onsubmit="handleFormSubmit(this)">
<h1><b>Health Points</b></h1>
<div class = "row">
<div class="col-md-2">
<label for="today">Date</label>
<input type="date" class="form-control" id="today" name="today" required>
</div>
</div>
<div class="row">
<div class="col-md-3">
<label for="food_name">Food Name:</label><br>
<select class="form-control" id="food_name" name="food_name" value="Select Food" required>
</select>
</div>
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="add" name="add">
<label class="form-check-label" for="flexCheckDefault">
Add New Food?
</label>
</div>
</div></div>
<div class="row">
<div class="col-md-4">
<label for="quantity">Quantity:</label><br>
<input id="quantity" type="number" step=".5" value="1" name="quantity">
</div>
</div><br>
<div class="row">
<div class="col-md-4">
<input id="smartpoints" type="text" placeholder="Health Points" name="smartpoints" readonly>
</div>
</div>
<!-- <br>
<div id="templateTotal"><p>Today's Total: <strong><?= total ?>/25</strong><br>
Points Remaining: <strong><?= remaining ?></strong></p></div> -->
<!-- Start section for adding foods -->
<div id="addfood" style="display:none;">
<br>
<div class="col-md-6">
<div class="card">
<div class="card-header">
Add a Food
</div>
<div class="container">
<div class="row">
<div class="col-md-4">
<label for="new_food_name">New Food Name:</label><br>
<input type="text" id="new_food_name" name="new_food_name">
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="serving_size_no">Serving Size #:</label>
<input type="number" id="serving_size_no" name="serving_size_no" step=".25">
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="serving_size_unit">Serving Size Unit:</label>
<input list="serving_size_unit_list" id="serving_size_unit" name="serving_size_unit">
<datalist id="serving_size_unit_list">
<option value="Cup(s)">
<option value="Ounce(s)">
<option value="Tbsp(s)">
<option value="Tsp(s)">
<option value="Gram(s)">
</datalist>
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="calories">Calories:</label>
<input type="number" id="calories" name="calories" step="1">
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="satfat">Saturated Fat:</label>
<input type="number" id="satfat" name="satfat">
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="satfat">Sugar:</label>
<input type="number" id="sugar" name="sugar">
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="protein">Protein:</label>
<input type="number" id="protein" name="protein">
</div>
</div><br>
</div>
</div>
</div></div><br>
<!-- End section for adding foods -->
<div class="col-md-4">
<button type="submit" class="btn btn-primary btn-block">Submit</button>
</div>
</form>
<div id="output"></div>
</div>
<script type="text/javascript">
document.getElementById("add").onchange = function(){
if (document.getElementById("add").checked) {
addfood.style.display = "block";
} else {
addfood.style.display = "none";
}
};
document.getElementById('food_name').onclick = function() {
var foodLookup = this.value;
google.script.run.withSuccessHandler(populateSmartpoints).getSmartPoints(foodLookup);
function populateSmartpoints(smartpointsPerServing){
var quantity = document.getElementById('quantity').value;
document.getElementById('smartpoints').value=smartpointsPerServing*quantity;
};
}
// Run function afterPageLoads once the page has loaded
document.addEventListener("DOMContentLoaded",afterPageLoads);
// Get drop down array for food names if that function is successful
function afterPageLoads() {
google.script.run.withSuccessHandler(afterDropDownArrayReturned).returnDropDownArray();
}
// Populate food name drop down with array from Google Sheets
function afterDropDownArrayReturned(arrayOfArrays) {
var item = document.getElementById("food_name");
console.log(item);
arrayOfArrays.forEach(function(r){
var option = document.createElement("option");
option.textContent = r[0];
item.appendChild(option);
});
}
// Update Smart Points if quantity is updated
document.getElementById('quantity').onchange = function() {
var sp = document.getElementById('smartpoints').value;
var quantity = document.getElementById('quantity').value;
document.getElementById('smartpoints').value=sp*quantity;
}
// Update food name if new food is added
document.getElementById('new_food_name').onchange = function() {
var newOption = document.getElementById('new_food_name').value;
if (newOption !==""){
var item = document.getElementById("food_name");
var option = document.createElement("option");
option.textContent = newOption;
item.appendChild(option);
var val = item.value;
item.value = newOption;
}
}
//Set today as the default date
n = new Date();
y = n.getFullYear();
m = n.getMonth() + 1;
d = n.getDate();
document.getElementById("today").value = y + "-" + m + "-" + d;
//Reload Page
</script>
</body>
</html>
This will sum column B in a linked sheet to a form from row 2 to the submitted row.
function onFormSubmit(e) {
const sh=e.range.getSheet();
const vals=sh.getRange(2,2,e.range.getRow()-1).getValues().flat();
let sum=vals.reduce(function(a,c){return a+=c;},0);
Logger.log(sum);
}
Remember the trigger requires an installable trigger.