How can I make a cell change colour every x seconds? - google-apps-script

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.

Related

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".

Are the csv files generated with parseCsv stored somewhere?

I'm doing a web in google script.
I have done the following search method:
https://script.google.com/macros/s/AKfycbzxWqtu9bIhTXb2zP9fsOoFFqe3St1T1C91ZDVu747GCWxrR1c/exec
my code Codigo.gs is:
function doGet(e) {
Logger.log(Utilities.jsonStringify(e));
if(!e.parameter.page){
return HtmlService.createTemplateFromFile("Index").evaluate();
}
var template=HtmlService.createTemplateFromFile(e.parameter.page)
template.action=ScriptApp.getService().getUrl();
return template.evaluate();
return HtmlService
.createHtmlOutputFromFile('Index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
/***************************** buscar asignado de trabajo ********************************************/
function get_AsignadoSS(k){
var sPers_asignado=k.pers_asignado;
var sReg_Asig="LIMA";
var contenido_ul="";
var spreadsheetId_r = '1ykYOd5PWP5aZEREnRIqkPMLT1pSYrcRA6mfQHl7bL4I'; // Please set the spreadsheet ID.
var targetSheet_r = 'Personal'; // Please set the sheet name.
if(sPers_asignado!="") {
var query_r = 'select A, B where ( B contains "'+sPers_asignado.toUpperCase()+'" or A contains "'+sPers_asignado.toUpperCase()+'" ) AND E = "'+sReg_Asig+'"'; // Please set the query for retrieving the values.
var ss_r = SpreadsheetApp.openById(spreadsheetId_r);
var sheetId_r = ss_r.getSheetByName(targetSheet_r).getSheetId();
var url_r = "https://docs.google.com/spreadsheets/d/" + spreadsheetId_r + "/gviz/tq?gid=" + sheetId_r + "&tqx=out:csv&tq=" + encodeURIComponent(query_r);
var res_r = UrlFetchApp.fetch(url_r, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
var row = Utilities.parseCsv(res_r.getContentText());
//https://docs.google.com/spreadsheets/d/1z4izqpus1yE6rZiqY1ttCEYA3NO3d7J3bZ4oFgQW330/gviz/tq?gid=Usuarios&tqx=out:csv&tq=encodeURIComponent('select A, B where ( B contains "li" )')
if(row.length>6){
var maximo=7;
}else{
var maximo=row.length;
}
//var contenido_ul=sCodigo_site;
var contenido_ul=contenido_ul+"<ul id='country-list' class='list-group'>";
for (var i = 1; i < maximo; i++) {
var nombre_site = row[i][1].toString();
var pasar_nom_site='"'+row[i][1].toString()+'"';
var contenido_ul=contenido_ul+"<li class='list-group-item' style='text-align: left' onClick='selectCountry("+pasar_nom_site+");'>"+nombre_site+"</li>";
}
var contenido_ul=contenido_ul+"</ul>";
}
if(sPers_asignado=="") {
var contenido_ul="";
}
return contenido_ul;
}
and my code Index.html is
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script>
function buscar_asignado(){
google.script.run.withSuccessHandler(get_Asignado).get_AsignadoSS(document.forms[0]);
}
function get_Asignado(data){
//alert("tt");
$("#suggesstion-box-asignado").show();
$("#suggesstion-box-asignado").html(data);
}
function selectCountry(codigo) {
$("#pers_asignado").val(codigo);
$("#suggesstion-box-asignado").hide();
}
/*----------------codigo esencial para conectar con codigo.GS----------------------*/
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);
</script>
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.3/css/responsive.bootstrap4.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/fixedheader/3.1.6/css/fixedHeader.dataTables.min.css">
</head>
<body>
<div class="modal-header" style="background-color: red;color: white;padding-top:5px;padding-bottom:5px">
<CENTER><label style="font-size: 30px;font-family: monospace;font-weight: normal;color:white">ACTIVIDADES</label></CENTER>
</div>
<div id="todo_contenido"style="display:block">
<center><br><br>
<div class="modal-content" style="width:95%">
<div class="modal-body">
<form id="datosTrabajo" name="datosTrabajo">
<div class="form-group row">
<label for="pers_asignado" class="col-sm-2 col-form-label">Asignado:</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="pers_asignado" name="pers_asignado" onkeyup="buscar_asignado();" placeholder="Nombre Asignado..." style="background-color: white">
<div id="suggesstion-box-asignado" style="position: absolute;z-index: 1"></div>
</div>
<label for="tipo_trabajo" class="col-sm-2 col-form-label">Tipo Trabajo:</label>
<div class="col-sm-4">
<select class="form-control" id="tipo_trabajo" name="tipo_trabajo" >
<option value="">Select Tipo Equipo:</option>
<option value="ATPs">ATPs</option>
<option value="Caceria Interferencia">Caceria Interferencia</option>
<option value="Desbalance RTWP">Desbalance RTWP</option>
<option value="Respaldo Baterias">Respaldo Baterias</option>
<option value="Site Audit">Site Audit</option>
<option value="Trabajos TX">Trabajos TX</option>
<option value="Prueba de Llamadas">Prueba de Llamadas</option>
<option value="PIM Logico">PIM Logico</option>
<option value="Administrativo">Administrativo</option>
<option value="OTROS">OTROS</option>
</select>
</div>
</div>
</form>
</div>
</div>
<br>
</center>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.20/js/dataTables.bootstrap4.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.3/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.3/js/responsive.bootstrap4.min.js"></script>
<script src="https://cdn.datatables.net/fixedheader/3.1.6/js/dataTables.fixedHeader.min.js"></script>
</body>
</html>
Then each time a letter is entered, a new search is made. In this case the search becomes normal, since it only occurs in 100 records. But my question is whether it is every time a new query is made (every time a digit is entered). These csv files are stored somewhere. The problem I have is that I have a more extensive code, which searches 6000 records; but you are not doing the search, and there are personnel who connect to this website to enter information and are having problems.
Or will there be some other way to do this type of search in Google Script?
parseCsv() - Returns a tabular 2D array representation of a CSV string. So
var A=Utilities.parseCsv(csvdata);
sheet.getRange(1,1,A.length,A[0].length).setValues(A);
will put the data into sheet.
The csv and the 2d array's are not stored anywhere unless you stored somewhere.

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

Countdown timer start/stop/reset button with Apps Script to Google Sheets

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

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