Countdown timer start/stop/reset button with Apps Script to Google Sheets - google-apps-script

I have some issues about countdown timer with start/stop/reset command button on Google Sheets . how to write a script for it by using google apps script, and put in google sheets, command by using start/stop/reset button.

A Javascript Timer for Gathering data off of a Spreadsheet
I built this as a test setup for one of my projects. Here's the datatimer.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<style>
#my_block{border:2px solid black;background-color:rgba(0,150,255,0.2);padding:10px 10px 10px 10px;}
#conv_block{border: 1px solid black;padding:10px 10px 10px 10px;}
.bttn_block{padding:5px 5px 0px 0px;}
.sndr_block {border:1px solid rgba(0,150,0,0.5);background-color:rgba(150,150,0,0.2);margin-bottom:2px;}
</style>
</head>
<body>
<form>
<div id="my_block" class="block form-group">
<div class="sndr_block">
<div id="myClock"></div>
<br />Timer Duration(minutes):
<br /><input id="txt1" type="text" size="4" class="action"/>
<select id="sel1" onChange="loadTxt('sel1','txt1');">
<option value="90000">1.5</option>
<option value="96000">1.6</option>
<option value="102000">1.7</option>
<option value="108000">1.8</option>
<option value="114000">1.9</option>
<option value="120000" selected>2.0</option>
<option value="126000">2.1</option>
<option value="132000">2.2</option>
<option value="138000">2.3</option>
<option value="144000">2.4</option>
</select>
<div id="cntdiv"></div>
<br /><strong>Timer Controls</strong>
<div class="bttn_block"><input type="button" value="Start" name="startShow" id="startShow" onClick="startmytimer();" class="red" /></div>
<div class="bttn_block"><input type="button" value="Stop" name="stopTimer" id="stopTimer" class="red" /></div>
<div class="bttn_block"><input type="button" value="Single Ping" name="changedata" id="chgData" class="red" onClick="changeData();" /></div>
</div>
<div id="btn-bar">
<br /><input type="button" value="Exit" onClick="google.script.host.close();" class="green" />
</div>
</div>
</form>
<script>
var idx=1;
var myInterval='';
var cnt=0;
$(function() {
$('#startTimer').click(startmytimer);
$('#stopTimer').click(stopTimer);
$('#txt1').val('120000');
startTime();
});
function startTime(){
var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
m = checkTime(m);
s = checkTime(s);
document.getElementById('myClock').innerHTML =
h + ":" + m + ":" + s;
var t = setTimeout(startTime, 500);
}
function checkTime(i){
if (i < 10) {i = "0" + i}; // add zero in front of numbers < 10
return i;
}
function startmytimer(){
document.getElementById('cntdiv').innerHTML='<strong>Timer Started:</strong> ' + document.getElementById('myClock').innerHTML;
myInterval=setInterval(changeData, Number($('#txt1').val()));
}
function stopTimer(){
document.getElementById('cntdiv').innerHTML='Timer Stopped';
clearInterval(myInterval);
}
function loadTxt(from,to){
document.getElementById(to).value = document.getElementById(from).value;
}
function changeData(){
$('#txt1').css('background','#ffffcc');
google.script.run
.withSuccessHandler(updateDisplay)
.changeData();
}
function updateDisplay(t){
$('#txt1').css('background','#ffffff');
document.getElementById('cntdiv').innerHTML='<strong>Timer Running:</strong> Count= ' + ++cnt + ' <strong>Time:</strong> ' + t;
}
console.log('My Code');
</script>
</body>
</html>
Here's the datachanger.gs file:
function changeData(){
var ss=SpreadsheetApp.getActive();
var sho=ss.getSheetByName('TradingTimes')
var tmr=Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "HH:mm:ss");
var col2=Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "E MMM dd,yyyy HH:mm:ss");
var col3=new Date(col2).getTime();
var col4=new Date(col2).getTime();
var dA=[[col2,col3,col4]];
sho.getRange('B2:D2').setValues(dA);
return tmr;
}
function showTimerSideBar()
{
var ui=HtmlService.createHtmlOutputFromFile('datatimer').setTitle('Javascript Trigger Generator');
SpreadsheetApp.getUi().showSidebar(ui);
}
I was just watching the output from a sheet that had Google Finance cell functions in it. But you can call anything you want as often as you like.
Here's what the dialog looks like:

You can attach actions to images in a google sheet. That way you can have a start, stop and reset buttons as images. When clicked the images can link to functions in the appscript which updates the time in single cell.
Below is the code, and here is a sample sheet . See the "attach action to images" document on how to trigger the buttons if needed.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
function countDownSeconds(seconds, minutes){
while (minutes >=0){
sheet.getRange(2,1).setValue(minutes);
while (seconds >= 0 ){
var m = sheet.getRange(2,1).getValue()
var s = sheet.getRange(2,2).getValue()
if (m === 'pausing' || s === 'pausing'|| m === 'reset' || s === 'reset' ) {
return
}
sheet.getRange(2,2).setValue(seconds);
SpreadsheetApp.flush();
Utilities.sleep(1000)
seconds --
}
seconds = 59;
minutes = sheet.getRange(2,1).getValue();
minutes --
}
}
function startTimer(){
var minutes = sheet.getRange(2,1).getValue()
var seconds = sheet.getRange(2,2).getValue()
countDownSeconds(seconds, minutes)
}
function pause(){
var minutes = sheet.getRange(2,1).getValue()
var seconds = sheet.getRange(2,2).getValue()
sheet.getRange(2,1).setValue('pausing');
sheet.getRange(2,2).setValue('pausing');
SpreadsheetApp.flush();
Utilities.sleep(1000);
sheet.getRange(2,1).setValue(minutes)
sheet.getRange(2,2).setValue(seconds)
}
function reset(){
sheet.getRange(2,1).setValue('reset');
sheet.getRange(2,2).setValue('reset');
SpreadsheetApp.flush();
Utilities.sleep(1000);
sheet.getRange(2,1).setValue(0)
sheet.getRange(2,2).setValue(0)
}

Related

Google Web App Dynamic Dependent Dropdown

I've been trying to add 3rd and 4th level dependent dropdown using the code from Code with Curt(https://codewithcurt.com/create-dependent-drop-down-on-google-web-app/), but I'm running into some issues. In this code below, I'm trying to add a 3rd level, but it doesn't seem to work. This is the output I'm trying to achieve. I'm not sure if there's a fastest way to load the dropdown from Google sheets, as this codes loads in about 3 seconds, or a better way to fetch it from Sheets.
Here's the code:
Google Apps Script:
function doGet(e) {
var htmlOutput = HtmlService.createTemplateFromFile('DependentSelect');
var colors = getColors();
htmlOutput.message = '';
htmlOutput.colors = colors;
return htmlOutput.evaluate();
}
function doPost(e) {
Logger.log(JSON.stringify(e));
var name = e.parameters.name.toString();
var color = e.parameters.color.toString();
var fruit = e.parameters.fruit.toString();
var class = e.parameters.class.toString(); //class is a reserved word
AddRecord(name, color, fruit, class);
var htmlOutput = HtmlService.createTemplateFromFile('DependentSelect');
var colors = getColors();
htmlOutput.message = 'Record Added';
htmlOutput.colors = colors;
return htmlOutput.evaluate();
}
function getColors() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var lovSheet = ss.getSheetByName("LOV");
var getLastRow = lovSheet.getLastRow();
var return_array = [];
for (var i = 2; i <= getLastRow; i++) {
if (return_array.indexOf(lovSheet.getRange(i, 1).getValue()) === -1) {
return_array.push(lovSheet.getRange(i, 1).getValue());
}
}
return return_array;
}
function getFruits(color) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var lovSheet = ss.getSheetByName("LOV");
var getLastRow = lovSheet.getLastRow();
var return_array = [];
for (var i = 2; i <= getLastRow; i++) {
if (lovSheet.getRange(i, 1).getValue() === color) {
return_array.push(lovSheet.getRange(i, 2).getValue());
}
}
return return_array;
}
function getClass(fruit) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var lovSheet = ss.getSheetByName("LOV");
var getLastRow = lovSheet.getLastRow();
var return_array = [];
for (var i = 2; i <= getLastRow; i++) {
if (lovSheet.getRange(i, 2).getValue() === fruit) {
return_array.push(lovSheet.getRange(i, 3).getValue());
}
}
return return_array.sort();
}
function AddRecord(name, color, fruit, class) {
var url = ''; //URL OF GOOGLE SHEET;
var ss = SpreadsheetApp.openByUrl(url);
var dataSheet = ss.getSheetByName("DATA");
dataSheet.appendRow([name, color, fruit, class, new Date()]);
}
function getUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
HTML:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
function GetFruit(color)
{
google.script.run.withSuccessHandler(function(ar)
{
console.log(ar);
fruit.length = 0;
let option = document.createElement("option");
option.value = "";
option.text = "";
fruit.appendChild(option);
ar.forEach(function(item, index)
{
let option = document.createElement("option");
option.value = item;
option.text = item;
fruit.appendChild(option);
});
}).getFruits(color);
};
function getClass(queue)
{
google.script.run.withSuccessHandler(function(ar)
{
console.log(ar);
class.length = 0;
let option = document.createElement("option");
option.value = "";
option.text = "";
class.appendChild(option);
ar.forEach(function(item, index)
{
let option = document.createElement("option");
option.value = item;
option.text = item;
class.appendChild(option);
});
}).getClass(queue);
};
</script>
<h1>Web App Dependent Drop Down</h1>
<?var url = getUrl();?>
<form method="post" action="<?= url ?>">
<label style="font-size: 20px" >Name</label><br>
<input type="text" name="name" style="font-size: 20px" /><br><br>
<label style="font-size: 20px" >Colors</label><br>
<select name="color" style="font-size: 20px" onchange="GetFruit(this.value)" >
<option value="" ></option>
<? for(var i = 0; i < colors.length; i++) { ?>
<option value="<?= colors[i] ?>" ><?= colors[i] ?></option>
<? } ?>
</select><br><br>
<label style="font-size: 20px" >Fruit</label><br>
<select name="fruit" id="fruit" style="font-size: 20px" >
</select><br><br>
<label style="font-size: 20px" >Class</label><br>
<select name="location" id="location" style="font-size: 20px" >
<option value="" selected disabled>Select Class</option>
</select><br><br>
<label style="font-size: 20px" >Brand</label><br>
<select name="location" id="location" style="font-size: 20px" >
<option value="" selected disabled>Select Brand</option>
</select><br><br>
<input type="submit" name="submitButton" value="Submit" style="font-size: 20px" />
<span style="font-size: 20px" ><?= message ?></span>
</form>
</body>
</html>
I believe your goal is as follows.
You want to reduce the process cost of your script.
Modification points:
When a loop process is used using the HTML template, the process cost becomes high. Ref
In this case, the HTML template is used for replacing the values.
When google.script.run is used, the process cost becomes high.
In this case, google.script.run is used for sending the values to the Google Apps Script side instead of the form submission.
From your showing script, I thought that the values might not be required to be sent with the HTML request. So, in this modification, the values are sent with google.script.run.
Creations of the options in the select tag are done in Javascript using the 1st loaded values.
In your Google Apps Script side, getValue() is used in a loop. In this case, the process cost becomes high. Ref
When these points are reflected in your showing script, how about the following modification?
Google Apps Script side:
function doGet(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("LOV");
var [, ...values] = sheet.getDataRange().getDisplayValues();
var htmlOutput = HtmlService.createTemplateFromFile('DependentSelect');
htmlOutput.values = JSON.stringify(values);
htmlOutput.message = '';
return htmlOutput.evaluate();
}
function addRecord({ name, color, fruit, clas, brand }) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DATA");
sheet.appendRow([name, color, fruit, clas, brand, new Date()]);
}
HTML & Javascript side:
<h1>Web App Dependent Drop Down</h1>
<form>
<label style="font-size: 20px" >Name</label><br>
<input type="text" name="name" style="font-size: 20px" /><br><br>
<label style="font-size: 20px" >Colors</label><br>
<select id="colors" name="color" style="font-size: 20px" onchange="setOptions('fruit', getValues(this.value, 0))" ></select><br><br>
<label style="font-size: 20px" >Fruit</label><br>
<select name="fruit" id="fruit" style="font-size: 20px" onchange="setOptions('clas', getValues(this.value, 1))" ></select><br><br>
<label style="font-size: 20px" >Class</label><br>
<select name="clas" id="clas" style="font-size: 20px" onchange="setOptions('brand', getValues(this.value, 2))" ></select><br><br>
<label style="font-size: 20px" >Brand</label><br>
<select name="brand" id="brand" style="font-size: 20px" ></select><br><br>
<input type="button" name="submitButton" value="Submit" style="font-size: 20px" onclick="sample(this.parentNode)" >
<span style="font-size: 20px" ><?= message ?></span>
</form>
<script>
const values = JSON.parse(<?= values ?>);
function setOptions(id, v) {
const s = document.getElementById(id);
s.innerHTML = "";
v.forEach(a => {
const option = document.createElement("option");
option.value = a;
option.innerHTML = a;
s.appendChild(option);
});
}
function getValues(e, i) {
return ["", ...new Set(values.reduce((ar, r) => (r[i] == e && ar.push(r[i + 1]), ar), []))];
}
window.onload = function() {
setOptions("colors", ["", ...new Set(values.map(([a]) => a))]);
}
function sample(e) {
google.script.run.addRecord(e);
}
</script>
Note:
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in the report "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
You may use the following GAS and HTML:
Google Apps Script
I have added the onlyUnique function (from another SO post) to filter out similar entries. I also added other functions to cater the Class and Brand columns. I also changed the variable class to classParam since class is a reserved word.
function doGet(e) {
var htmlOutput = HtmlService.createTemplateFromFile('DependentSelect');
var colors = getColors();
var fruits = getFruits();
var classParams = getClasses();
var brands = getBrands();
htmlOutput.message = '';
htmlOutput.colors = colors;
htmlOutput.fruits = fruits;
htmlOutput.classParams = classParams;
htmlOutput.brands = brands;
return htmlOutput.evaluate();
}
function doPost(e) {
Logger.log(JSON.stringify(e));
var name = e.parameters.name.toString();
var color = e.parameters.color.toString();
var fruit = e.parameters.fruit.toString();
var classParam = e.parameters.classParam.toString();
var brand = e.parameters.brand.toString();
AddRecord(name, color, fruit, classParam, brand);
var htmlOutput = HtmlService.createTemplateFromFile('DependentSelect');
var colors = getColors();
var fruits = getFruits();
var classParams = getClasses();
var brands = getBrands();
htmlOutput.message = 'Record Added';
htmlOutput.colors = colors;
htmlOutput.fruits = fruits;
htmlOutput.classParams = classParams;
htmlOutput.brands = brands;
return htmlOutput.evaluate();
}
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
function getColors() {
var ss= SpreadsheetApp.getActiveSpreadsheet();
var lovSheet = ss.getSheetByName("LOV");
var getLastRow = lovSheet.getLastRow();
var return_array = [];
for(var i = 2; i <= getLastRow; i++)
{
if(return_array.indexOf(lovSheet.getRange(i, 1).getValue()) === -1) {
return_array.push(lovSheet.getRange(i, 1).getValue());
}
}
return return_array.filter(onlyUnique);
}
function getFruits(color) {
var ss= SpreadsheetApp.getActiveSpreadsheet();
var lovSheet = ss.getSheetByName("LOV");
var getLastRow = lovSheet.getLastRow();
var return_array = [];
for(var i = 2; i <= getLastRow; i++)
{
if(lovSheet.getRange(i, 1).getValue() === color) {
return_array.push(lovSheet.getRange(i, 2).getValue());
}
}
return return_array.filter(onlyUnique);
}
function getClasses(color, fruit) {
var ss= SpreadsheetApp.getActiveSpreadsheet();
var lovSheet = ss.getSheetByName("LOV");
var getLastRow = lovSheet.getLastRow();
var return_array = [];
for(var i = 2; i <= getLastRow; i++)
{
if((lovSheet.getRange(i, 1).getValue() === color) && (lovSheet.getRange(i, 2).getValue() === fruit)) {
return_array.push(lovSheet.getRange(i, 3).getValue());
}
}
return return_array.filter(onlyUnique);
}
function getBrands(color, fruit, classParam) {
var ss= SpreadsheetApp.getActiveSpreadsheet();
var lovSheet = ss.getSheetByName("LOV");
var getLastRow = lovSheet.getLastRow();
var return_array = [];
for(var i = 2; i <= getLastRow; i++)
{
if((lovSheet.getRange(i, 1).getValue() === color) && (lovSheet.getRange(i, 2).getValue() === fruit) && (lovSheet.getRange(i, 3).getValue() === classParam)) {
return_array.push(lovSheet.getRange(i, 4).getValue());
}
}
return return_array.filter(onlyUnique);
}
function AddRecord(name, color, fruit, classParam, brand) {
var url = ""; //INSERT SPREADSHEET URL HERE <---------
var ss = SpreadsheetApp.openByUrl(url);
var dataSheet = ss.getSheetByName("DATA");
dataSheet.appendRow([name, color, fruit, classParam, brand, new Date()]);
}
function getUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
HTML
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function GetFruit(color)
{
google.script.run.withSuccessHandler(function(ar)
{
console.log(ar);
fruit.length = 0;
let option = document.createElement("option");
option.value = "";
option.text = "";
fruit.appendChild(option);
ar.forEach(function(item, index)
{
let option = document.createElement("option");
option.value = item;
option.text = item;
fruit.appendChild(option);
});
}).getFruits(color);
};
function GetClass(color, fruit)
{
google.script.run.withSuccessHandler(function(ar)
{
console.log(ar);
classParam.length = 0;
let option = document.createElement("option");
option.value = "";
option.text = "";
classParam.appendChild(option);
ar.forEach(function(item, index)
{
let option = document.createElement("option");
option.value = item;
option.text = item;
classParam.appendChild(option);
});
}).getClasses(color, fruit);
};
function GetBrand(color, fruit, classParam)
{
google.script.run.withSuccessHandler(function(ar)
{
console.log(ar);
brand.length = 0;
let option = document.createElement("option");
option.value = "";
option.text = "";
brand.appendChild(option);
ar.forEach(function(item, index)
{
let option = document.createElement("option");
option.value = item;
option.text = item;
brand.appendChild(option);
});
}).getBrands(color, fruit, classParam);
};
</script>
</head>
<body>
<h1>Web App Dependent Drop Down</h1>
<?var url = getUrl();?>
<form method="post" action="<?= url ?>" >
<!-- name -->
<label style="font-size: 20px" >Name</label><br>
<input type="text" name="name" style="font-size: 20px" /><br><br>
<!-- color -->
<label style="font-size: 20px" >Colors</label><br>
<select name="color" id="color" style="font-size: 20px" onchange="GetFruit(this.value)" >
<option value="" ></option>
<? for(var i = 0; i < colors.length; i++) { ?>
<option value="<?= colors[i] ?>" ><?= colors[i] ?></option>
<? } ?>
</select><br><br>
<!-- fruit -->
<label style="font-size: 20px" >Fruits</label><br>
<select name="fruit" id="fruit" style="font-size: 20px" onchange="GetClass(color.value, this.value)" >
<option value="" ></option>
<? for(var i = 0; i < fruits.length; i++) { ?>
<option value="<?= fruits[i] ?>" ><?= fruits[i] ?></option>
<? } ?>
</select><br><br>
<!-- class -->
<label style="font-size: 20px" >Classes</label><br>
<select name="classParam" id="classParam" style="font-size: 20px" onchange="GetBrand(color.value, fruit.value, this.value)" >
<option value="" ></option>
<? for(var i = 0; i < classParams.length; i++) { ?>
<option value="<?= classParams[i] ?>" ><?= classParams[i] ?></option>
<? } ?>
</select><br><br>
<!-- brand -->
<label style="font-size: 20px" >Brand</label><br>
<select name="brand" id="brand" style="font-size: 20px" >
</select><br><br>
<input type="submit" name="submitButton" value="Submit" style="font-size: 20px" />
<span style="font-size: 20px" ><?= message ?></span>
</form>
</body>
</html>
Sample Data
Web App
Output

Add fields to this html form who add/edit data in a spreadsheet

I found the scripts below on this post, and I tried to figure out how to add a new column on the sheet and make it work with the html form the same way as the two columns already existing
But without success...
If someone can take the time to explain to me how to do it, it would be very nice 🙏
The HTML /CSS side and basic JS are understandable for me but the rest stay hard to understand by myself
Here the sheet sample
Thanks !
CODE.GS
function doGet(request) {
return HtmlService.createTemplateFromFile('Form').evaluate();
}
/* #Include JavaScript and CSS Files */
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
/* Find ID*/
function getID(IDsearch){
var url = "https://docs.google.com/spreadsheets/d/1QESrQb4rYhmr0uc7q6ptvmdmMbo0Bxp_hZrvKaobdI8/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Database");
/*set cells to plain text*/
var range = ws.getRange(1, 1, ws.getMaxRows(), ws.getMaxColumns());
range.setNumberFormat("#");
var data = ws.getRange(3, 1, ws.getLastRow(), 2).getValues();
var dataInput = data.map(function(r){return r[1];}); //ID column
var position = dataInput.indexOf(IDsearch); //index of the row where ID is
Logger.log(position);
var dataArray = ws.getRange(position+3, 1, 1, 2).getValues(); //array with data from searched ID
var clientsDataString = dataArray.toString();
var clientsDataArray = clientsDataString.split(',');
if(position > -1){
return clientsDataArray;
} else {
return position;
}
}
function processForm(formObject) {
var url = "https://docs.google.com/spreadsheets/d/1QESrQb4rYhmr0uc7q6ptvmdmMbo0Bxp_hZrvKaobdI8/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Database");
var ranges = ws.getRange(4, 2, ws.getLastRow() - 3, 1).createTextFinder(formObject.ID).findAll();
if (ranges.length > 0) {
for (var i = 0; i < ranges.length; i++) {
ranges[i].offset(0, -1, 1, 2).setValues([[formObject.name, formObject.ID]]);
}
} else {
ws.appendRow([formObject.name, formObject.ID]);
}
}
JavaScript.html
<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);
function handleFormSubmit(formObject) {
google.script.run.processForm(formObject);
document.getElementById("myForm").reset();
}
/* Search for ID */
document.getElementById("btn-procurar").addEventListener("click", onSearch);
function onSearch() {
var IDsearch = document.getElementById("insertID").value;
google.script.run.withSuccessHandler(populateForm).getID(IDsearch);
}
function populateForm(clientsData) {
document.getElementById("name").value = clientsData[0];
document.getElementById("ID").value = clientsData[1];
}
</script>
form.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="/Contact-Form-Clean.css">
<link rel="stylesheet" href="/styles.css">
<?!= include('JavaScript'); ?>
<?!= include('form-css'); ?>
</head>
<body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="register-photo" style="padding-top: 30px;">
<div class="form-container" style="width: 695px;">
<form id="myForm" onsubmit="handleFormSubmit(this)" method="post" style="width: 720px;padding: 10px;padding-right: 20px;padding-left: 25px;">
<input class="form-control" type="text" id="name" name="name" placeholder="Name" style="width: 300px;display: inline-block;margin-bottom: 20px;">
<input class="form-control" type="number" id="ID" name="ID" placeholder="ID" style="width: 165px;display: inline-block;" required="">
<button type="submit" id="btn-submeter" onclick="return confirm('Submit?')" class="btn btn-primary btn-block" style="width: 644px;margin-bottom: 35px;">Save data</button>
<script>
document.getElementById("myForm").addEventListener("submit", myFunction);
function myFunction() {
alert("Success");
}
</script>
<div id="output"></div>
<div style="margin-bottom: 15px;padding: 5px;background-color: rgba(255,255,255,0);padding-top: 0px;border-top: double;">
<h6 class="text-left" style="margin-top: 15px;display: inline-block;width: 519px;margin-right: 20px;margin-bottom: 10px;">Search/Fetch ID</h6>
<input class="form-control" type="text" id="insertID" name="insertID" placeholder="Insert ID" style="width: 155px;display: inline-block;">
<button class="btn btn-primary" id="btn-procurar" onclick="onSearch()" type="button" style="width: 450px;margin: 10px 0px 25px 0px;padding: 6px;margin-top: 0px;margin-bottom: 0px;margin-left: 29px;">Search by ID</button>
</div>
</form>
</div>
</div>
<script src="/js/jquery-3.4.1.min.js"></script>
<script src="/bootstrap/js/bootstrap.min.js"></script>
</body>
</html>
You want to put the values of "name", "ID", "address", "email" and "phone" using the HTML form.
In your updated shared Spreadsheet, 5 input tags are put.
You want to achieve this by modifying your script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification points:
In your current script, 2 values are used like [formObject.name, formObject.ID].
For this, please modify to 5 values like [formObject.name, formObject.ID, formObject.address, formObject.email, formObject.phone].
modified script
When your script is modified, it becomes as follows.
From:
function processForm(formObject) {
var url = "https://docs.google.com/spreadsheets/d/1QESrQb4rYhmr0uc7q6ptvmdmMbo0Bxp_hZrvKaobdI8/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Database");
var ranges = ws.getRange(4, 2, ws.getLastRow() - 3, 1).createTextFinder(formObject.ID).findAll();
if (ranges.length > 0) {
for (var i = 0; i < ranges.length; i++) {
ranges[i].offset(0, -1, 1, 2).setValues([[formObject.name, formObject.ID]]);
}
} else {
ws.appendRow([formObject.name, formObject.ID]);
}
}
To:
function processForm(formObject) {
var url = "https://docs.google.com/spreadsheets/d/1QESrQb4rYhmr0uc7q6ptvmdmMbo0Bxp_hZrvKaobdI8/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Database");
var ranges = ws.getRange(4, 2, ws.getLastRow() - 3, 1).createTextFinder(formObject.ID).findAll();
var v = [formObject.name, formObject.ID, formObject.address, formObject.email, formObject.phone]; // Added
if (ranges.length > 0) {
for (var i = 0; i < ranges.length; i++) {
ranges[i].offset(0, -1, 1, v.length).setValues([v]); // Modified
}
} else {
ws.appendRow(v); // Modified
}
}
Note:
In your updated shared Spreadsheet, type="number" is used for the input tag of phone. In this case, for example, when the value is 01 33 33 33 33 33, an error occurs because 01 33 33 33 33 33 is not the number. If you want to show 01 33 33 33 33 33, please modify to type="string".

How can I make a cell change colour every x seconds?

So I am working on a document on google sheets and I want it to look nice, this code really is unimportant but it would great to know how to do it, as every bit I learn anyways, can help in the future.
Something a bit more technical could be 1 cell changes to a certain colour, then the other cell identifies that that cell has changed colour so it also changes colour, and it keeps going until it loops on the last cell (to kind of create a rainbow effect).
Please remember though, a lot of conditional formatting is unavailable in google docs sheets and you can't use macros, you have to use Google Sheet Script.
Change color every x seconds
Code.gs:
function onOpen(){
SpreadsheetApp.getUi().createMenu('MyTools')
.addItem('Show Sidebar', 'showTimerSideBar')
.addToUi();
}
function showTimerSideBar()
{
var ui=HtmlService.createHtmlOutputFromFile('datatimer').setTitle('Color Timer');
SpreadsheetApp.getUi().showSidebar(ui);
}
function changeData(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('ColorChange');
var rg=sh.getRange('A1:A10');
var colorA=rg.getBackgrounds();
var n=new Date();
var tmr=Utilities.formatDate(n, Session.getScriptTimeZone(), "HH:mm:ss")
var rObj={color:colorA[Math.floor(Math.random()*colorA.length)][0],timer:tmr};
ss.toast(Utilities.formatString('timer: %s color: %s', rObj.timer,rObj.color));
return rObj;
}
function saveData(dObj) {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Data');
var lr=sh.getLastRow();
sh.getRange(lr+1,1).setValue(dObj.timer);
sh.getRange(lr+1,2).setBackground(dObj.color);
}
function setA1(color) {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('ColorChange');
var rg=sh.getRange('A1');
rg.setBackground(color);
}
datatimer.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<style>
#my_block{border:2px solid black;background-color:rgba(0,150,255,0.2);padding:10px 10px 10px 10px;}
#conv_block{border: 1px solid black;padding:10px 10px 10px 10px;}
.bttn_block{padding:2px 5px 0px 0px;}
.sndr_block {border:1px solid rgba(0,150,0,0.5);background-color:rgba(150,150,0,0.2);margin-bottom:2px;}
</style>
</head>
<body>
<form>
<div id="my_block" class="block form-group">
<div class="sndr_block">
<div id="myClock" style="font-size:20px;font-weight:bold;"></div>
<br />Timer Duration(seconds):
<br /><input id="txt1" type="text" size="4" class="action"/>
<select id="sel1" onChange="loadTxt('sel1','txt1');">
</select>
<div id="cntdiv"></div>
<br /><strong>Timer Controls</strong>
<div class="bttn_block"><input type="button" value="Start" name="startShow" id="startShow" onClick="startmytimer();changeData();" class="red" /></div>
<div class="bttn_block"><input type="button" value="Stop" name="stopTimer" id="stopTimer" class="red" /></div>
<div class="bttn_block"><input type="button" value="Single Ping" name="changedata" id="chgData" class="red" onClick="changeData();" /></div>
<div class="bttn_block"><input type="button" value="Red" name="setA1Red" id="setRed" class="red" onClick="setA1('#ff0000');" /></div>
<div class="bttn_block"><input type="button" value="Green" name="setA1Green" id="setGreen" class="green" onClick="setA1('#00ff00');" /></div>
</div>
<div id="btn-bar">
<br /><input type="button" value="Exit" onClick="google.script.host.close();" class="green" />
</div>
</div>
</form>
<script>
var idx=1;
var myInterval='';
var cnt=0;
$(function() {
var select = document.getElementById('sel1');
select.options.length = 0;
for(var i=1;i<61;i++)
{
select.options[i-1] = new Option(i,i * 1000);
}
select.selectedIndex=4;
$('#startTimer').click(startmytimer);
$('#stopTimer').click(stopTimer);
$('#txt1').val(String(select.options[select.selectedIndex].value));
startTime();
});
function startTime(){
var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
m = checkTime(m);
s = checkTime(s);
document.getElementById('myClock').innerHTML =
h + ":" + m + ":" + s;
var t = setTimeout(startTime, 500);
}
function checkTime(i){
if (i < 10) {i = "0" + i}; // add zero in front of numbers < 10
return i;
}
function startmytimer(){
document.getElementById('cntdiv').innerHTML='<strong>Timer Started:</strong> ' + document.getElementById('myClock').innerHTML;
myInterval=setInterval(changeData, Number($('#txt1').val()));
}
function stopTimer(){
document.getElementById('cntdiv').innerHTML='Timer Stopped';
clearInterval(myInterval);
}
function loadTxt(from,to){
document.getElementById(to).value = document.getElementById(from).value;
}
function exportData() {
google.script.run.saveData(cA);
}
function changeData(){
$('#txt1').css('background','#ffffcc');
google.script.run
.withSuccessHandler(function(rObj){
updateDisplay(rObj.timer);
saveData({timer:rObj.timer,color:rObj.color});
$('#txt1').css('background','#ffffff');
})
.changeData();
}
function updateDisplay(t){
$('#txt1').css('background','#ffffff');
document.getElementById('cntdiv').innerHTML='<strong>Timer Running:</strong> Count= ' + ++cnt + ' <strong>Time:</strong> ' + t;
}
function setA1(color) {
console.log(color);
google.script.run.setA1(color);
}
function saveData(dObj) {
google.script.run.saveData(dObj);
}
console.log('My Code');
</script>
</body>
</html>
Current Colors: (ColorChange Sheet)
Data Sheet:
Timer Sidebar:
I modified an existing script to provide you with this example. So there may be other unrelated scripts in here. Feel free to modify it to fit your specific needs.

Round robin assignment of tasks - AppScript solution?

I have a form response sheet (https://docs.google.com/spreadsheets/d/1YCneMRUC6ZKK0V3qs0mROhr6j62mdNIWAxcW71aAQIg/edit#gid=0) which saves all the requests from our stakeholders, and our workflow lead has to manually assign these requests to the members of our team in a round-robin fashion while ensuring each of the team members has an equal distribution of requests.
However, if a duplicate task is submitted (which is very much possible), it should be assigned to the same person that handled it earlier.
Is it possible to employ Google scripts solution to get this type of random yet equal distribution of tasks among the assignee group? The agent availability on any given day is also important, as they could be out of office, therefore the workflow lead keeps revising the agent list almost on a daily basis. Hence, it's all the more useful to have a Google AppScript solution to this problem (assigning one task at a time to the next available agent in queue). If the script can email the agent that would be ideal, but not necessary. Kindly advise! Thanks.
Round Robin Assignment
This script provides the following assignments:
If task title is repeated it assigns that task to original assignee.
If task title is new then it assigns that task to the assignee that has the least tasks.
If the title is new and all assignees have the same number of tasks then it makes a random selection with Math.floor(Math.random() * assigneeArray.length);
Here's the code:
Code.gs:
function onOpen() {
SpreadsheetApp.getUi().createMenu('My Tools')
.addItem('Add Task', 'addTask')
.addItem('Add Assignee', 'addAssignee')
.addSubMenu(SpreadsheetApp.getUi().createMenu('Utility')
.addItem('Select Columns Skip Header', 'jjeSUS1.selectColumnsSkipHeader')
.addItem('Create Named Range', 'jjeSUS1.createNamedRange'))
.addToUi();
}
function addAssignee() {
showFormDialog({filename:'addAssignee',title:'Add Assignee'});
}
function postAssigneeData() {
}
function addTask() {
showFormDialog({filename:'addTask',title:'Add Task'});
}
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function showFormDialog(dObj){
var form=HtmlService.createHtmlOutputFromFile(dObj.filename).getContent();
var ui=HtmlService.createTemplateFromFile('html').evaluate();
ui.append(form);
ui.append("</body></html>");
SpreadsheetApp.getUi().showModelessDialog(ui, dObj.title);
}
function saveData(dObj) {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName(dObj.sheetName);
var hrg=sh.getRange(1,1,1,sh.getLastColumn());
var hA=hrg.getValues()[0];
var vA=[];
for(var i=0;i<hA.length;i++) {
vA.push((dObj[hA[i]])?dObj[hA[i]]:'');//Column headers must agree with form names
}
dObj['row']=sh.getLastRow()+1;
var cA=Object.keys(dObj).filter(function(el){return (el!=='row' && el !='sheetName')});
for(var i=0;i<cA.length;i++) {
saveValue(dObj.row,cA[i],dObj[cA[i]],dObj.sheetName,1);
}
return dObj;
}
function makeAssignment(aObj) {
Logger.log(aObj);
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Assignments')
var title=aObj.Title;
var taskObj=getTasks();
//Check to see if someone has already done this once
if(taskObj.taskA.indexOf(title)>-1) {
saveValue(aObj.row,'Assignment',taskObj[aObj.Title],'Assignments',1);
saveValue(aObj.row,'Date',Utilities.formatDate(new Date(),Session.getScriptTimeZone(), "E MM d, yyyy HH:mm"),'Assignments',1);
postTaskData(aObj.Title,taskObj[aObj.Title]);
}else{
var assA=getAssigneeTasks();
if(assA[0].allCountsEqual=='false') {
//they don't have the same number of tasks so take the lowest one
saveValue(aObj.row,'Assignment',assA[0].email,'Assignments',1);
saveValue(aObj.row,'Date',Utilities.formatDate(new Date(),Session.getScriptTimeZone(), "E MM d, yyyy HH:mm"),'Assignments',1);
postTaskData(aObj.Title,assA[0].email);
}else{
//they all have the same number of task so take a random one
var n=Math.floor(Math.random()*assA.length);
saveValue(aObj.row,'Assignment',assA[n].email,'Assignments',1);
saveValue(aObj.row,'Date',Utilities.formatDate(new Date(),Session.getScriptTimeZone(), "E MM d, yyyy HH:mm"),'Assignments',1);
postTaskData(aObj.Title,assA[n].email);
}
}
return true;
}
function getTasks() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Data');
var taskObj={'taskA':[]};
var h=jjeSUS1.getColumnHeight(1, sh, ss);
if(h>2) {
var rg=sh.getRange(3,1,h-2,2);
var vA=rg.getValues();
for(var i=0;i<vA.length;i++) {
taskObj[vA[i][0]]=vA[i][1];
if(taskObj.taskA.indexOf(vA[i][0])==-1) {
taskObj.taskA.push(vA[i][0]);//Unique Task Array
}
}
}
return taskObj
}
function postTaskData(key,value) {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Data');
sh.appendRow([key,value]);
}
function getAssigneeTasks() {
var taskObj=getTasks();
var aeqA=getAssignees().map(function(el){return {email:el,count:0,allCountsEqual:'false'}});
var keysA=Object.keys(taskObj).filter(function(el){return (el != 'taskA')});
for(var i=0;i<aeqA.length;i++) {
for(var j=0;j<keysA.length;j++) {
if(taskObj[keysA[j]]==aeqA[i].email){
aeqA[i].count+=1;
}
}
}
aeqA.sort(function(a,b){return a.count - b.count;});
var isTrue=true;
var maxCount=aeqA[aeqA.length-1].count;
aeqA.forEach(function(el){if(el.count!=maxCount){isTrue=false;}});
if(isTrue) {
aeqA.map(function(el){return el.allCountsEqual='true';});
}
return aeqA;
}
function saveValue(row,columnName,value,sheetName,headerRow) {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName(sheetName);
var hA=sh.getRange(headerRow,1,1,sh.getLastColumn()).getValues()[0];
sh.getRange(row,hA.indexOf(columnName)+1).setValue(value);
}
function getAssignees() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Assignees');
var hrg=sh.getRange(1,1,1,sh.getLastColumn());
var hA=hrg.getValues()[0];
return sh.getRange(2, hA.indexOf('Email')+1, sh.getLastRow()-1,1).getValues().map(function(r){return r[0]});
}
function closeDialog() {
var userInterface=HtmlService.createHtmlOutputFromFile('dummy');
SpreadsheetApp.getUi().showModelessDialog(userInterface,'Closing');
}
css.html:
<style>
body {background-color:#ffffff;}
input[type="button"],input[type="text"]{margin:0 0 2px 0;}
</style>
resources.html:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
html.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('resources') ?>
<?!= include('css') ?>
<?!= include('script') ?>
</head>
<body>
script.html:
<script>
$(function(){
document.getElementById('txt1').focus();
});
function getInputObject(obj) {
var rObj={};
var length=Object.keys(obj).length;
for(var i=0;i<length;i++){
console.log('Name: %s Type: %s',obj[i].name,obj[i].type);
if(obj[i].type=="text"){
rObj[obj[i].name]=obj[i].value;
}
if(obj[i].type=="select-one"){
rObj[obj[i].name]=obj[i].options[obj[i].selectedIndex].value;
}
if(obj[i].type="hidden"){
if(obj[i].name) {
rObj[obj[i].name]=obj[i].value;
}
}
}
return rObj;
}
function processForm(obj){
var fObj=getInputObject(obj);
console.log(JSON.stringify(fObj));
google.script.run
.withSuccessHandler(function(rObj){
document.getElementById("btn").disabled=true;
$('#msg').html('<br /><h1>Data Saved.</h1>');
if(rObj.sheetName=='Assignments') {
google.script.run
.withSuccessHandler(function(){
$('#msg').html('<br /><h1>Assignments Complete.</h1>');
google.script.host.close();
})
.makeAssignment(rObj);
}else{
google.script.host.close();
}
})
.saveData(fObj);
}
console.log('My Code');
</script>
addAssignee.html:
<div id="heading"><h1>Add Assignee</h1></div>
<div id="content">
<h3>Please Enter First Name, Last Name, Phone and Email into the text areas adjacent to the text box labels.</h3>
<form id="assigneeForm" onsubmit="event.preventDefault();processForm(this);" >
<br /><input type="text" id="txt1" name="First" /> First
<br /><input type="text" id="txt2" name="Last" /> Last
<br /><input type="text" id="txt3" name="Phone" /> Phone
<br /><input type="text" id="txt3" name="Email" /> Email
<br /><input type="hidden" value="Assignees" name="sheetName" />
<br /><input id="btn" type="submit" value="Submit" />
<br />
</form>
</div>
<div id="msg"></div>
<div id="cntl"><input type="button" id="btn" value="Close" onClick="google.script.host.close();" ></div>
addTask.html:
<div id="heading"><h1>Add Task</h1></div>
<div id="content">
<h3>Please Enter Title and Description into the text areas adjacent to the text box labels.</h3>
<form id="assigneeForm" onsubmit="event.preventDefault();processForm(this);" >
<br /><input type="text" id="txt1" name="Title" /> Title
<br /><input type="text" id="txt2" name="Description" /> Description
<br /><input type="hidden" value="Assignments" name="sheetName" />
<br /><input id="btn" type="submit" value="Submit" />
<br />
</form>
</div>
<div id="msg"></div>
<div id="cntl"><input type="button" id="btn" value="Close" onClick="google.script.host.close();" ></div>
The three pages of my spreadsheet look as follows: (names are on images)
JavaScript Arrays
JavaScript Objects
HtmlService
Templated Html
Public Libraries

I need with parsing an array from google script to HTML

I have a date picker that I'd like to use to choose an event and then show details from a spread sheet.
HTML:
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Datepicker - Default functionality</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.0/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<script>
$(function() {
$( "#datepicker" ).datepicker({
onSelect: function(date) {
var stuff= updDate(date);
},
selectWeek: true,
inline: true,
startDate: '01/01/2000',
firstDay: 1,
});
});
</script>
<script>
function updDate(date){
google.script.run.updDate(date);
}
</script>
</head>
<body>
<p>Date: <input type="text" id="datepicker" onchange="updDate()"></p>
Hello, world!
<input type="button" value="Close"
onclick="google.script.host.close()" />
</body>
</html>
Google Script:
function updDate(date){
var searchString = date;
var data = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var s2 = SpreadsheetApp.openById("*************");
var row = new Array();
var k;
for (var i in data) {
//Logger.log("length is: "+data[i].length)
//var p = data[i].length
for (var j in data[i]) {
//Logger.log("We are at i: "+i) //Row
//Logger.log("We are at j: "+j) //Col
if (i !=0){
if(data[i][j] != ""){
if(j == 4){
//Logger.log("date from picker: " + date);
//Logger.log("date from Data: " + data[i][j]);
var ssDate = Utilities.formatDate(data[i][j], "GMT", "MM/dd/yyyy");
//Logger.log("date post Convert: " +ssDate);
if(date == ssDate){
k= i
var p = data[i].length
Logger.log("P is: " +p);
}
}
}
}
}
}
Logger.log("K is: "+k)
var q = 1
while (q <= p){
row[q] = data[k][q];
q++
}
Logger.log("Row: " +row);
return row;
}
Eventually I'd like to get the data read into a table but I've been hitting a wall when it comes to successfully getting the data read into a variable in the HTML.
Right now I get this error:
Uncaught ScriptError: The script completed but the returned value is not a supported return type.
Any help in returning the array "row"(in the google script) to the variable "stuff"(in the HTML) successfully or any pointers about how to better execute this task would be greatly appreciated.
Loren
Edit code:
function updDate(date){
var stuff = google.script.run.withSuccessHandler(myReturnFunction).updDate(date);
Console.log(stuff)
}
function myReturnFunction(){
window.myReturnFunction = function(whatGotReturned) {console.log(whatGotReturned);};
}
Sandy Good had it right in the comments above:
function updDate(date){
var junk = google.script.run.withSuccessHandler(myReturnFunction).updDate(date);
}
function myReturnFunction(whatGotReturned){
console.log(whatGotReturned);
}