Apps Script: Collect Form Input and Display Today's Total - google-apps-script

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.

Related

I have a problem with the submit buttom it should button for my websocket chat application, when i try to submit it won't come out it's just blank

like in this picture, if I try to send a message it can come out but if try to submit a file or image it won't come out. this is my code below
enter image description here
<p id="demo"></p>
<div id="messages">
<div id="time"></div>
</div>
<form>
<input type="" placeholder="write a message">
<input type="file" id="myfile" name="myfile">
<button type="submit" class="submit">Send</button>
</form>
<script>
var date = new Date();
var time = date.getHours() + ":" + date.getMinutes() ;
function showMessage(text,isMine = false) {
document.getElementById("messages").innerHTML += `
<div class="message-row ${isMine?'mine':'theirs'}">
<div class="bubble">${text}</div>
<div class="time">${time}</div>
</div>
`;
}
const ws = new WebSocket('ws://localhost:8080');
ws.addEventListener('message', ev => {
ev.data.text().then(showMessage);
});
document.querySelector('form').onsubmit = ev => {
ev.preventDefault();
const input = document.querySelector('input');
ws.send(input.value);
showMessage(input.value, true);
input.value = '';
}

upload files into google drive folder from side bar UI

I am trying to make web app as a sidebar in spreadsheet using HTML5, Bootstrap 5 & JavaScript to make entry of data easier . I managed to go through the entire process But the problem that I can't make the button upload files into google drive folder and return with the url back.
the link of sheet working with.
I think the problem in this variable from html script but I don't know what is it
var url = document.getElementById("transaction-file").addEventListener('click',
function(a){
google.script.run.uploadFiles(this.parentNode)
});
https://docs.google.com/spreadsheets/d/1D-tEPsUJqGbCHrF8CYQlPu_ZhmVIGDYEojHfO0_7rW4/edit?usp=sharing
google script code
function loadForm() {
const htmlForSidebar = HtmlService.createTemplateFromFile("uform");
const htmlOutput = htmlForSidebar.evaluate();
htmlOutput.setTitle("Winter 2021");
const ui = SpreadsheetApp.getUi();
ui.showSidebar(htmlOutput);
}
function createMenu(){
const ui = SpreadsheetApp.getUi();
const menu = ui.createMenu("My Forms");
menu.addItem("Show UserForm", "loadForm");
menu.addToUi();
}
function onOpen(){
createMenu();
}
function uploadFiles(files){
var file = files.myFile;
var folder = DriveApp.getFolderById('1gaNAb1s8j7wmotvRUJbg4yfJOFNdZYo5');
var createFile = folder.createFile(file);
return createFile.geturl();
}
function addNewRow(rowData) {
const currentDate = new Date();
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Sheet1");
ws.appendRow([currentDate, rowData.trxDate, rowData.account, rowData.trxID, rowData.amount, rowData.url, rowData.comment]);
return true;
}
function getDropDownArray(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Ref");
return ws.getRange(2, 1, ws.getLastRow()-1, 1).getValues();
}
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<div class="container pt-3">
<h4 class="border-bottom pb-2 mb-4">Donations' Registration <span class="badge bg-secondary">Form</span></h4>
<div id="userform">
<div class="mb-3">
<label for="transaction-date" class="form-label">Transaction Date</label>
<input type="date" class="form-control" id="transaction-date" required>
<div class="invalid-feedback">Please enter valid date.</div>
</div>
<div class="mb-3">
<label for="transaction-account" class="form-label">Account</label>
<select class="form-select" id="transaction-account" required aria-label="select account" required>
</select>
<div class="invalid-feedback">Please enter valid account.</div>
</div>
<div class="mb-3">
<label for="transaction-id" class="form-label">Transaction ID</label>
<input type="text" class="form-control" id="transaction-id" required>
<div class="invalid-feedback">Please enter valid ID.</div>
</div>
<div class="mb-3">
<label for="transaction-amount" class="form-label">Amount</label>
<input type="number" class="form-control" id="transaction-amount" required>
<div class="invalid-feedback">Please enter valid amount without any service fees.</div>
</div>
<div class="mb-3">
<label for="transaction-file" class="form-label">url</label>
<input type="file" class="form-control" id="transaction-file" name="myFile" aria-label="file example" required>
<div class="invalid-feedback">Please upload right file.</div>
</div>
<div class="mb-3">
<label for="transaction-memo" class="form-label">Memo</label>
<textarea class="form-control" id="transaction-memo" rows="1"></textarea>
</div>
<div class="mb-3">
<button class="btn btn-primary" id="mainButton">Add to Database</button>
</div>
</div>
</div>
<!-- Optional JavaScript; choose one of the two! -->
<!-- Option 1: Bootstrap Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<!-- Option 2: Separate Popper and Bootstrap JS -->
<!--
<script src="https://cdn.jsdelivr.net/npm/#popperjs/core#2.10.2/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
-->
<script>
function afterButtonClicked(){
if(validate()){
var trxDate = document.getElementById("transaction-date");
var account = document.getElementById("transaction-account");
var trxID = document.getElementById("transaction-id");
var amount = document.getElementById("transaction-amount");
var url = document.getElementById("transaction-file");
var comment = document.getElementById("transaction-memo");
var rowData = {trxDate: trxDate.value, account: account.value, trxID: trxID.value, amount: amount.value, url: url.value, comment: comment.value};
google.script.run.withSuccessHandler(afterSubmit).addNewRow(rowData);
} else {
//handle this later
}
}
function afterSubmit(e){
clearFields(["transaction-date", "transaction-account", "transaction-id", "transaction-amount", "transaction-file", "transaction-memo"]);
}
function clearFields(fields){
fields.forEach(function(field){
var el = document.getElementById(field);
el.value = "";
});
}
function validate(){
var fieldsToValidate = document.querySelectorAll("#userform input, #userform select");
//is-invalid
Array.prototype.forEach.call(fieldsToValidate,function(el){
if(el.checkValidity()){
el.classList.remove("is-invalid");
} else {
el.classList.add("is-invalid");
}
});
return Array.prototype.every.call(fieldsToValidate,function(el){
return el.checkValidity();
});
}
function afterSidebarLoads(){
google.script.run.withSuccessHandler(afterDropDownArrayReturned).getDropDownArray();
}
function afterDropDownArrayReturned(arrayOfArrays){
var account = document.getElementById("transaction-account");
arrayOfArrays.forEach(function(r){
var option = document.createElement("option");
option.textContent = r[0];
account.appendChild(option);
});
}
document.getElementById("mainButton").addEventListener("click",afterButtonClicked);
google.script.run.uploadFiles(this.parentNode);
document.addEventListener("DOMContentLoaded",afterSidebarLoads);
</script>
</body>
</html>

Display a data according to the choice of several menus in cascade (Google Script)

I am developing a tool that allows to collect requests via a form created on Google Script.
The user selects via cascading drop-down menus the site, the area, the zone and finally the room for which he wants to make his request.
I would like to be able to display the manager who corresponds to the selected room but I can't. There shouldn't be much to change but I can only display in relation to the selected area.
Here are the different codes used:
server side code :
function getQtyOnHand(site, secteur, zone, salle){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Table");
const data = ws.getRange(2, 1, ws.getLastRow()-1, 7).getValues();
var filtre = {};
const filteredData = data.filter(r => r[0] === site && r[1] === secteur && r[2] === zone && r[4] === salle);
filtre.filtreSecteur = filteredData.length === 0 ? 0 : filteredData.reduce((subtotal, r) => subtotal + r[6],"");
return filtre;
}
the code's functions on the front side
function updatedQtyOnHand(){
var site = document.getElementById("item-site").value;
var secteur = document.getElementById("item-secteur").value;
var zone = document.getElementById("item-zone").value;
google.script.run.withSuccessHandler(afterQtyOnHandReturned).getQtyOnHand(site,secteur,zone);
}
function afterQtyOnHandReturned(qty){
document.getElementById("on-hand").textContent = "";
var responsable = qty.filtreSecteur.split("#");
var nomPrenomResp = responsable[0];
var adresseResponsable = nomPrenomResp+"#test.com";
document.getElementById("on-hand").textContent = adresseResponsable;
}
the html's code on the front side to show responsable (sorry for the indentation but every time I publish here, I have to redo it with spaces and I'm struggling):
<!-- HTML DU FORMULAIRE -->
<div id="userform" class="userForm">
<h1 class="mb-5" id="titreFormulaire">FORMULAIRE DEMANDE TRAVAUX NEUFS</h1>
<div class="row mt-5 ml-3 mr-3">
<!-- Sélection du lieu -->
<div class="blocEndroitFull">
<!-- Choix du site -->
<div class ="blocEndroit">
<label for="item-site" id="labelSite">Site :</label>
<select class="form-control" id="item-site">
</select>
</div>
<!-- Choix du secteur -->
<div class ="blocEndroit">
<label for="item-secteur" id="labelSecteur">Secteur :</label>
<select class="form-control" id="item-secteur">
</select>
</div>
<!-- Choix de la zone -->
<div class ="blocEndroit">
<label for="item-zone" id="labelZone">Désignation zone :</label>
<select class="form-control" id="item-zone">
</select>
</div>
<!-- Choix de la salle -->
<div class ="blocEndroit">
<label for="item-salle" id="labelSalle">Salle :</label>
<select class="form-control" id="item-salle">
</select>
</div>
</div>
<!-- Affichage du responsable -->
<div id="responsable">
<span class="input-group-text" id="txt-responsable">Responsable :
<span class="ml-1">
<span id="on-hand"></span>
</span>
</span>
</div>
<!-- Plan -->
<div class="col-12">
<img id="image" width="80%" class ="rounded mx-auto d-block image">
</div>
<!-- Description -->
<hr width="100%" color="black">
<div class="form-group" id="descriptionBloc">
<label for="delivery-note"><b>Veuillez décrire votre demande en quelques mots :</b></label>
<textarea type="text" class="form-control" id="delivery-note" rows="5" cols="100" required></textarea>
<div class="invalid-feedback">Décrivez votre demande</div>
</div>
<!-- Informations complémentaires (checklists) -->
<div id="infoComplementairesFull">
<div class="blocInfos">
<label for="date-received"><b>Délai :</b></label>
<div class="form-check">
<input class="form-check-input" type="radio" name="radio" id="trimestre" value="trimestre" required>
<label class="form-check-label" for="trimestre">Trimestre</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="radio" id="semestre" value="semestre">
<label class="form-check-label" for="semestre">Semestre</label>
<div class="invalid-feedback">Choisissez un délai.</div>
</div>
</div>
<div class="blocInfos">
<label for="item-inter"><b>Intervention possible en production :</b></label>
<div class="form-check">
<input class="form-check-input" type="radio" name="radio2" id="interOui" value="oui">
<label class="form-check-label" for="interOui">Oui</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="radio2" id="interNon" value="non" checked>
<label class="form-check-label" for="interNon">Non</label>
</div>
</div>
<div class="blocInfos">
<label for="item-dispo"><b>Disponibilité de la zone :</b></label>
<div class="form-check">
<input class="form-check-input" type="radio" name="radio3" id="dispoNon" value="zone toujours disponible">
<label class="form-check-label" for="dispoNon">Zone toujours disponible</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="radio3" id="dispoOui" value="travaux à planifier" checked>
<label class="form-check-label" for="dispoOui">Travaux à planifier</label>
</div>
</div>
<div class="blocInfos">
<label><b>Budget est-il prévu ?</b></label>
<div class="form-check">
<input class="form-check-input" type="radio" name="radio4" id="budgetNon" value="non">
<label class="form-check-label" for="budgetNon">
Non
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="radio4" id="budgetNeSaitPas" value="ne sait pas" checked>
<label class="form-check-label" for="budgetNeSaitPas">
Ne sait pas
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="radio4" id="budgetOui" value="oui">
<label class="form-check-label" for="budgetOui">
Oui
</label>
</div>
<div id="idBudget" class="input-group input-line mb-1 d-none">
<input id="inputIdBudget" list="listeBudget" name="radio4" type="text" class="form-control" placeholder="ID budget ...">
</div>
</div>
Choisissez une photo de près :
Choisissez une photo de près
Choisissez une photo de loin :
Choisissez une photo de loin
Envoyer Demande
Confirmation
×
the link to the Sheet file if you want to look at it by yourself :
link
a screenshot of the form:
I tried the code below but it doesn't work and I don't understand why
server side code :
function getQtyOnHand(site, secteur, zone, salle){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Table");
const data = ws.getRange(2, 1, ws.getLastRow()-1, 7).getValues();
var filtre = {};
const filteredData = data.filter(r => r[0] === site && r[1] === secteur && r[2] === zone && r[4] === salle);
filtre.filtreSecteur = filteredData.length === 0 ? 0 : filteredData.reduce((subtotal, r) => subtotal + r[6],"");
return filtre;
}
the code's function on the front side :
function updatedQtyOnHand(){
var site = document.getElementById("item-site").value;
var secteur = document.getElementById("item-secteur").value;
var zone = document.getElementById("item-zone").value;
var zone = document.getElementById("item-salle").value;
google.script.run.withSuccessHandler(afterQtyOnHandReturned).getQtyOnHand(site,secteur,zone,salle);
}
the code's function where i used updatedQtyOnHand's function (in dropdown's menus:
function afterDropDownArrayReturned(arrayOfArrays){
arrayOfValues = arrayOfArrays.filter(function(r){ return true; });
var item = document.getElementById("item-site");
addUniqueOptionsToDropdownList(item,arrayOfValues,0);
afterFirstDropDownChanged();
afterSecondDropDownChanged();
afterThirdDropDownChanged();
}
function addUniqueOptionsToDropdownList(el,arrayOfArrays,index){
var currentlyAdded = [];
el.innerHTML = '';
arrayOfArrays.forEach(function(r){
if(currentlyAdded.indexOf(r[index]) === -1){
var option = document.createElement("option");
option.textContent = r[index];
el.appendChild(option);
currentlyAdded.push(r[index]);
}
});
var option = document.createElement("option");
option.textContent = "Non défini";
el.appendChild(option);
}
function afterFirstDropDownChanged(){
var itemSecteur = document.getElementById("item-secteur");
var secteur = document.getElementById("item-site").value;
var filteredArrayOfValues = arrayOfValues.filter(function(r){ return r[0] === secteur });
addUniqueOptionsToDropdownList(itemSecteur,filteredArrayOfValues,1);
afterSecondDropDownChanged();
updatedQtyOnHand();
}
function afterSecondDropDownChanged(){
var itemZone = document.getElementById("item-zone");
var site = document.getElementById("item-site").value;
var itemSecteur = document.getElementById("item-secteur").value;
var filteredArrayOfValues = arrayOfValues.filter(function(r){ return r[0] === site && r[1] === itemSecteur});
addUniqueOptionsToDropdownList(itemZone,filteredArrayOfValues,2);
updatedQtyOnHand();
}
function afterThirdDropDownChanged(){
var itemZone = document.getElementById("item-zone").value;
var site = document.getElementById("item-site").value;
var itemSecteur = document.getElementById("item-secteur").value;
var itemSalle = document.getElementById("item-salle");
var filteredArrayOfValues = arrayOfValues.filter(function(r){ return r[0] === site && r[1] === itemSecteur && r[2] === itemZone});
addUniqueOptionsToDropdownList(itemSalle,filteredArrayOfValues,4);
updatedQtyOnHand();
}
Thanks in advance for your help and sorry for my poor English.
As I committed yesterday, here is a html template focused on dependent cascading dropdown (4 levels) with sources fetched from google sheet.
On gs side:
function transfertHeaders() {
var bdd = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('DB')
return JSON.stringify(bdd.getRange(1,1,1,bdd.getLastColumn()).getValues())
}
function transfertData() {
var bdd = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('DB')
return JSON.stringify(bdd.getRange(2,1,bdd.getLastRow(),bdd.getLastColumn()).getValues())
}
on html side:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
<?
var headers = JSON.parse(transfertHeaders());
?>
var data = JSON.parse(<?=transfertData()?>);
window.onload = function() {
var level1sel = document.getElementById("level1");
var level2sel = document.getElementById("level2");
var level3sel = document.getElementById("level3");
var level4sel = document.getElementById("level4");
var dico = new Map()
for (var i = 0; i < data.length; i++) {
dico.set(data[i][0],"")
}
dico.forEach(function(value, key) {
level1sel.options[level1sel.options.length] = new Option(key, key);
})
level1sel.onchange = function(){
level2sel.length = 1;
level3sel.length = 1;
level4sel.length = 1;
dico.clear()
for (var i = 0; i < data.length; i++) {
if (data[i][0]==this.value) {dico.set(data[i][1],"")}
}
dico.forEach(function(value, key) {
level2sel.options[level2sel.options.length] = new Option(key, key);
})
}
level2sel.onchange = function(){
level3sel.length = 1;
level4sel.length = 1;
var select1 = document.getElementById('level1');
var value1 = select1.options[select1.selectedIndex].value;
dico.clear()
for (var i = 0; i < data.length; i++) {
if (data[i][1]==this.value && data[i][0]==value1) {dico.set(data[i][2],"")}
}
dico.forEach(function(value, key) {
level3sel.options[level3sel.options.length] = new Option(key, key);
})
}
level3sel.onchange = function(){
level4sel.length = 1;
var select1 = document.getElementById('level1');
var value1 = select1.options[select1.selectedIndex].value;
var select2 = document.getElementById('level2');
var value2 = select2.options[select2.selectedIndex].value;
dico.clear()
for (var i = 0; i < data.length; i++) {
if (data[i][2]==this.value && data[i][0]==value1 && data[i][1]==value2) {dico.set(data[i][3],"")}
}
dico.forEach(function(value, key) {
level4sel.options[level4sel.options.length] = new Option(key, key);
})
}
}
</script>
<h3>Cascading Dropdown</h3>
<form name="form" id="form" >
<?!= headers[0][0] ?>: <select name="level1" id="level1">
<option value="" selected="selected">Select <?!= headers[0][0] ?></option>
</select>
<br>
<?!= headers[0][1] ?>: <select name="level2" id="level2">
<option value="" selected="selected">Please select <?!= headers[0][0] ?> first</option>
</select>
<br>
<?!= headers[0][2] ?>: <select name="level3" id="level3">
<option value="" selected="selected">Please select <?!= headers[0][1] ?> first</option>
</select>
<br>
<?!= headers[0][3] ?>: <select name="level4" id="level4">
<option value="" selected="selected">Please select <?!= headers[0][2] ?> first</option>
</select>
<br>
</form>
</body>
</html>
var zone
is re-defined again just after first definition. It should be salle.

Google Spread Sheet Search any part of the cell and display

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;
}

Calculate a total from autocomplete suggestion.data

I'm trying to write a small Jquery program with an autocomplete searchform. I would like the user to be able to add items from the autocomplete form to a sort of shopping list. I have difficulties finding a way to calculate and update the total price of all added products, I tried to store the prices, which are in suggestion.data and tot add it recusively to a total as in
total = total + suggestion.data, but this seems not to be the way. Could someone help me to produce and display this total? My jQuery code is as follows:
var Price = {};
var Name = {};
var Totaal = {};
$(function () {
var currencies = [
{value:'TEXT-STRING',data:'5.50)'},
{value:'TEXT-STRING2',data:'3.10)'},
];
$('#autocomplete').autocomplete({
lookup: currencies,
onSelect: function (suggestion) {
Price.fff = suggestion.data;
Name.fff = suggestion.value;
},
});
});
function addListItem() {
var write2 = Price.fff;
var write = $('#autocomplete').val();
var list = $('#itemList');
var item = $('<li><span class="list">' + write + '</span><button
class="delete">X</button></li>');
var autocomplete = $("#autocomplete");
if (write.length === 0 || write.length > 88) {
return false;
}
if (write == Name.fff) {
list.append(item);
list2.append(item2);
$(autocomplete).val('');
}
$(autocomplete).val('');
}
function deleteItem() {
$(this).parent().remove();
}
$(function () {
var add = $('#addItem');
var autocomplete = $('#autocomplete');
var list = $('#itemList');
add.on('click', addListItem);
list.on('click', '.delete', deleteItem);
autocomplete.on('keypress', function (e) {
if (e.which == 13) {
addListItem();
}
}
And my HTML looks like:
<body>
<div id="box-1"> </div>
<div id="box-2"> </div>
<div id="page">
<h1>Shop</h1>
</div>
<div id="main">
<div id="top">
<div id="form">
<div id="searchfield">
<input type="text" id="autocomplete" name="currency" class="biginput" placeholder="ADD ITEMS BELOW">
<input type="submit" id="addItem" value="+">
</div>
<div class="line"> </div>
</div>
<div id="bottom">
<div class="items">
<ul id="itemList">
</ul>
</div>
</div>
Keep added item in array with prices, so you can recalculate total at any time. Don't forget to remove it from array when removing from the list.
Don't keep data in DOM, use DOM only to display info that is in your model.