I have a Google site and am currently using the following script to populate my select box with data from the google sheet that is serving as my database:
<? var stringified = getData(); ?>
<?var data = JSON.parse(stringified)?>
<select size="10" id="userChoice">
<? for (var i = 0; i < data.length; i++) { ?>
<option>
<?= data[i] ?>
<? } ?>
</select>
This loads the page with the select box populated with every entry in the database. I'm wondering if this is the best way to go about it. What I would really like to do is have the contents of the select box be a little more dynamic.
I wrote out a script to filter through (by date) the contents of the Google Sheet, but I can't quite figure out how to have those filtered results show up in the above select box. I've tried several possible solutions, but keep hitting road blocks with them. Below is the function on the client side that passes the dates to the server side (note that I realize nothing in the below scripts would pass the data back to the select box. This is just to show how I am filtering through the data):
//Takes the dates that were entered into the first two date pickers and sends them over to the server side stringified. The server side then uses these dates to filter out jobs not within the given time period.
function dateFilter(){
var date = {};
//dates pusehd into array
date[0] = document.getElementById("startDate").value;
date[1] = document.getElementById("endDate").value;
//array stringified
var dates = JSON.stringify(date);//Convert object to string
google.script.run
.getData2(dates);
Then here is the code that filters through the database on the server side:
function getData2(dates) {
var ss = SpreadsheetApp.openById('1emoXWjdvVmudPVb-ZvFbvnP-np_hPExvQdY-2tOcgi4').getSheetByName("Sheet1");
var date = JSON.parse(dates);
var dateArray = [];
for (var k in date) {//Loop through every property in the object
var thisValue = date[k];//
dateArray.push(thisValue);
};
var startDate = Date.parse(dateArray[0]);
var endDate = Date.parse(dateArray[1]);
var jobReference = [];
var job;
var dateCell1;
var dateCell;
if ((startDate==NaN) || (endDate==NaN)){
for (var i = 2; job!=""; i++){
job = ss.getRange(i,43).getValue();
jobReference.push(job);
};
}
else{
for (var i = 2; job!=""; i++){
dateCell1 = ss.getRange(i,3).getValue();
dateCell = Date.parse(dateCell1);
if (startDate<=dateCell&&endDate>=dateCell){
job = ss.getRange(i,43).getValue();
jobReference.push(job);
Logger.log("here it is"+jobReference);
}
else{
}
}
};
var jR = JSON.stringify(jobReference);
return jR;
}
Now I've tried several things, having a success handler change the line <? var stringified = getData();?> to use getData2 doesn't seem to work (it yells at me that variable I'm trying to parse is undefined on the server side). So I tried putting an if/else in that would only have it parse if the variable was != to undefined, that didn't work either. Any suggestions would be appreciated.
I figured it out! This is functional, but perhaps not best practices, so if someone has any input, feel free to chime in.
So the first bit of code on the client side for the select box I left the same.
The next bit, where I send the dates over to the server side was changed to this:
function dateFilter(){
var sdate = document.getElementById("startDate").value;
var edate = document.getElementById("endDate").value;
google.script.run.withSuccessHandler(dateSuccess)
.getData2(sdate,edate);
}
So, since it was only two variables I took out the part that pushed it to an array. This eliminated the problem of parsing on the server side and thus having an undefined variable. I also added a success handler.
The server side code was left essentially the same, however I did change the for loop slightly. Instead of having it loop through the database until it found a blank cell in a particular column, I added var last = ss.getLastRow(); and had it loop though until i<= last. This kept the code from timing out on me.
Next I added the function I used for the success handler:
function dateSuccess(jobs){
document.getElementById('userChoice').options.length = 0;
var data = JSON.parse(jobs)
for (var i = 0; i < data.length; i++) {
var option = document.createElement("option");
option.text = data[i]
var select = document.getElementById("userChoice");
select.appendChild(option);
}
}
Works like a charm!
Scriptlets i.e. <? ?> are compiled and run when the page is created using execute function. They are not for dynamic modification of the web page. To modify the options based on a server returned data, in this case from getData(). You would do something like this
Firstly you set your google.script to call modifyoptions function on success
google.script.run.withSuccessHandler(modifyOptions)
.getData2(dates);
The above will code will automatically pass the return value of getData2 i.e Jr value to modifyOptions function
function modifyOptions(jobReference){
var selOpt = document.getElementById("userChoice")
selOpt.innerHTML ="" // Remove previous options
var options = ""
var data = JSON.parse(jobReference)
for (var i = 0; i < data.length; i++) {
options += "<option>"+data[i] +</option> //New string of options based on returned data
}
selOpt.innerHTML = options //Set new options
}
You can find a working example of how to modify the select-options in javascript here
Hope that helps!
Related
I just signed up and need help with a problem, I am new to the google app scripts and I am struggling to create a script to avoid duplicate date.
The sheet will capture data once a day and to avoid duplicate dates I am trying to write a script.
I have looked at different methods, tried arrays and that also wont seem to work.
I created a small test site to explain here with the current issue I am facing.
Below is the code when the user clicks a save button, please not I am only struggling with the if statement. I get all the dates but I am unable to break it into separate dates in order to do the if statement.
In your code the variable values is indeed an array retrieved from your sheet using getValues()
You can manipulate that array as you loop through it removing the duplicate based on your variable names date or load into a separate array
var i = 0;
var lenValues = values.length;
var newArray = [];
for (i = 0; i < lenValues; i++) {
if (date !== values[i]) {
newArray.push(values[i]);
}
}
Now, dates can be tricky, I would use the debugger and set a breakpoint to inspect the data format stored in the values variable and adjust accordingly.
Once you have the new array, you may decide to write those values to another sheet
writeDataToSheet(newArray, "Target sheet name");
// Writes a 2D array of data to sheet
function writeDataToSheet(data, sheetName) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
goToSheet(sheetName, ss);
var sheet = ss.getActiveSheet();
var range = sheet.getRange("A1:A");
range.clear();
// write date to active sheet starting at the 2nd row
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
return sheet.getName();
}
function goToSheet(sheetName, ss) {
ss.setActiveSheet(ss.getSheetByName(sheetName));
}
Now, if all you want to do is alert the user the data already exists try this instead:
var i = 0;
var found = false;
var lenValues = values.length;
for (i = 0; i < lenValues; i++) {
if (date == values[i]) {
found = true;
break;
}
}
Put this before your if statement and change to:
if (found) {
}
This code will work to remove duplicates. My original dates are in C9:C16
The problem here is that it has converted the dates into strings, you may need to convert back to dates.
function removeDuplicate(){
var sheet = SpreadsheetApp.getActive().getActiveSheet();
let originalDates = sheet.getRange('C9:C16').getDisplayValues().flat();
console.log(originalDates);
let datesNoDup = originalDates.filter((date,i) => originalDates.indexOf(date) == i);
console.log(datesNoDup);
}
7:14:26 AM Notice Execution started
7:14:27 AM Info [ '2/1/2011',
'2/1/2011',
'2/25/2011',
'3/17/2011',
'7/25/2011',
'10/19/2011',
'3/17/2011',
'7/25/2011' ]
7:14:27 AM Info [ '2/1/2011',
'2/25/2011',
'3/17/2011',
'7/25/2011',
'10/19/2011' ]
7:14:27 AM Notice Execution completed
```
I'm working on a project that take "profiles" stored in a Google Sheet, makes a unique Google Doc for each profile, and then updates the unique Google Doc with any new information when you push a button on the Google Sheet.
I have some other automations built into my original code, but I simplified most of it to what's pertinent to the error I'm getting, which is this:
Exception: Document is missing (perhaps it was deleted, or you don't have read access?
It happens on Line 52 of my script in the fileUpdate funtion. Here's the appropriate line for reference:
var file = DocumentApp.openById(fileName);
And this is the rest of my code:
function manageFiles() {
//Basic setup. Defining the range and retrieving the spreadsheet to store as an array.
var date = new Date();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var array = sheet.getDataRange().getValues();
var arrayL = sheet.getLastRow();
var arrayW = sheet.getLastColumn();
for (var i = 1; i < arrayL; i++) {
if (array[i][arrayW-2] == "") {
//Collect the data from the current sheet.
//Create the document and retrieve some information from it.
var docTitle = array[i , 0]
var doc = DocumentApp.create(docTitle);
var docBody = doc.getBody();
var docLink = doc.getUrl();
//Use a for function to collect the unique data from each cell in the row.
docBody.insertParagraph(0 , "Last Updated: "+date);
for (var j = 2; j <= arrayW; j++) {
var colName = array[0][arrayW-j];
var data = array[i][arrayW-j];
if (colName !== "Filed?") {
docBody.insertParagraph(0 , colName+": "+data);
}
}
//Insert a hyperlink to the file in the cell containing the SID
sheet.getRange(i+1 , 1).setFormula('=HYPERLINK("'+docLink+'", "'+SID+'")');
//Insert a checkbox and check it.
sheet.getRange(i+1 , arrayW-1).insertCheckboxes();
sheet.getRange(i+1 , arrayW-1).setFormula('=TRUE');
}
else if (array[i][arrayW-2] !== "") {
updateFiles(i);
}
}
sheet.getRange(1 , arrayW).setValue('Last Update: '+date);
}
//Note: I hate how cluttered updateFiles is. I'm going to clean it up later.
function fileUpdate(rowNum) {
//now you do the whole thing over again from createFiles()
//Basic setup. Defining the range and retrieving the spreadsheet to store as an array.
var date = new Date();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var array = sheet.getDataRange().getValues();
var arrayL = sheet.getLastRow();
var arrayW = sheet.getLastColumn();
//Collect the data from the current sheet.
var fileName = array[rowNum][0];
var file = DocumentApp.openById(fileName);
//retrieve the body of the document and clear the text, making it blank.
file.getBody().setText("");
//Use a for function to collect the the unique date from every non-blank cell in the row.
file.getBody().insertParagraph(0 , "Last Updated: "+date);
for (var j = 2; j <= arrayW; j++) {
var colName = array[0][arrayW-j];
var data = array[rowNum][arrayW-j];
file.getBody().insertParagraph(0 , colName+": "+data);
}
}
If you'd like to take a look at my sample spreadsheet, you can see it here. I suggest you make a copy though, because you won't have permissions to the Google Docs my script created.
I've looked at some other forums with this same error and tried several of the prescribed solutions (signing out of other Google Accounts, clearing my cookies, completing the URL with a backslash, widening permissions to everyone with the link), but to no avail.
**Note to anyone offended by my janky code or formatting: I'm self-taught, so I do apologize if my work is difficult to read.
The problem (in the updated code attached to your sheet) comes from your URL
Side Note:
In your initial question, you define DocumentApp.openById(fileName);
I assume your realized that this is not correct, since you updated
your code to DocumentApp.openByUrl(docURL);, so I will discuss the
problem of the latter in the following.
The URLs in your sheet are of the form
https://docs.google.com/open?id=1pT5kr7V11TMH0pJea281VhZg_1bOt8YDRrh9thrUV0w
while DocumentApp.openByUrl expects a URL of form
https://docs.google.com/document/d/1pT5kr7V11TMH0pJea281VhZg_1bOt8YDRrh9thrUV0w/
Just adding a / is not enough!
Either create the expected URL manually, or - much easier / use the method DocumentApp.openById(id) instead.
For this, you can extract the id from your URL as following:
var id = docURL.split("https://docs.google.com/open?id=")[1];
var file = DocumentApp.openById(id)
I am a novice here to google app scripts and my JavaScript is also not very strong, but neither of these seem to be the problem here as my code works the first time I run it but then when I try to call it again it fails.
Simply I am trying to have a function that will dynamically find a given text in a given range. While it looks like there might be a built in package that does this I cannot figure out how to implement it. And the documentation is not helpful for someone new.
Option 1: was to implement the following: https://developers.google.com/apps-script/reference/spreadsheet/text-finder#findAll()
Since that has not been sucessful in finding out how to do it I moved to creating the following simple two functions, Option 2:
function findIndexRow(range,fText){
for(var i = 0; i<range.length;i++){
for(var j = 0; j<range.length;j++){
if(range[i][j] == fText){
var fTextRow = i+1;
var fTextCol = j+1;
}
}
}
return fTextRow
}
function findIndexCol(range,fText){
for(var i = 0; i<range.length;i++){
for(var j = 0; j<range.length;j++){
if(range[i][j] == fText){
var fTextRow = i+1;
var fTextCol = j+1;
}
}
}
return fTextCol
}
It takes in a range that I defined like:
var sheet = SpreadsheetApp.openById('the-gsheet-id');
var CurrSheet = sheet.getSheetByName('Sheet1');
var SHTvalues = CurrSheet.getDataRange().getValues();
So the above works when I call it once in my main code but the second time it returns null, help here as to why re calling the same function does not work.
var text1Row = findIndexRow(SHTvalues,"text1");
var text1Col = findIndexCol(SHTvalues,"text1");
Logger.log(text1Row)
Logger.log(text1Col)
var text2Row = findIndexRow(SHTvalues,"text2");
var text2Col = findIndexCol(SHTvalues,"text2");
Logger.log(text2Col)
Logger.log(text2Row)
I can't understand why my logs return the correct values for text1Row and text1Col but when it is called a second time the text2Row and text2Col both return null
I believe your goal as follows.
You want to search a text value from a sheet in the Google Spreadsheet, and want to retrieve the row and column numbers of the found values.
You want to achieve this using TextFinder.
For this, how about this answer?
Sample script:
var findText = "text1";
var sheet = SpreadsheetApp.openById('the-gsheet-id');
var CurrSheet = sheet.getSheetByName('Sheet1');
var SHTvalues = CurrSheet.createTextFinder(findText).findAll();
var result = SHTvalues.map(r => ({row: r.getRow(), col: r.getColumn()}));
console.log(result)
Note:
About my logs return the correct values for text1Row and text1Col but when it is called a second time the text2Row and text2Col both return null in your script, if there are the values of text1 and text2 in Sheet1, text1Row, text1Col, text2Col and text2Row has the values. If only the value of text1 is put in Sheet1, text1Col and text2Col has the values. But text2Col and text2Row has no values (null). Please be careful this.
But in this case, when 2 values of `text1 are put to the cells "A1" and "A2", only "A2" is returned. Also please be careful this.
In this sample script, please enable V8.
References:
createTextFinder() in Class Sheet
Class TextFinder
Here's a script that I used for searching through my spreadsheets when I'm having trouble finding the sheet I want. It does read another sheet to get a list of spreadsheets to search through.
function regexSearch(sObj) {
var ass=SpreadsheetApp.getActive();
var startRow=2;
var msrsh=ass.getSheetByName('MultiSearchResults');
msrsh.clearContents();
msrsh.appendRow(['Path','FileName','FileId','SheetName','CellA1Notation','Value','Pattern']);
msrsh.activate();
var sh=ass.getSheetByName('SelectedSpreadsheets');
var hA=sh.getRange(1,1,1,sh.getLastColumn()).getValues()[0];
var getArrayIndex={};
hA.forEach(function(e,i){getArrayIndex[e]=i;});
var rg=sh.getRange(startRow,1,sh.getLastRow()-startRow+1,sh.getLastColumn());
var ssA=rg.getValues();
var matches='';
var n=0
for(var k=0;k<ssA.length;k++) {
var fileid=ssA[k][getArrayIndex['FileId']];
var filename=ssA[k][getArrayIndex['FileName']];
var filepath=getFilePathFromId(ssA[k][getArrayIndex['FileId']]);
//Logger.log(fileid);
var ss=SpreadsheetApp.openById(fileid);
Logger.log(sObj.pattern);
var tf=ss.createTextFinder(sObj.pattern).useRegularExpression(true);
var all=tf.findAll();
for(var i=0;i<all.length;i++) {
if(i==0)n++;
matches+=Utilities.formatString('<br /><b>Path:</b> %s <b>Sheet:</b> %s <b>Cell:</b> %s <b>Value:</b> %s<hr width="100%"/>',filepath,all[i].getSheet().getName(),all[i].getA1Notation(),all[i].getValue());
msrsh.appendRow([filepath,filename,fileid,all[i].getSheet().getName(),all[i].getA1Notation(),all[i].getValue(),sObj.pattern]);
}
}
if(matches) {
sObj.matches=matches;
sObj.message=Utilities.formatString('<p>Pattern %s was found in %s spreadsheet out of a total of %s</p>',sObj.pattern,n,ssA.length);
}else{
sObj.message=Utilities.formatString('No Matches found for %s',sObj.pattern);
}
return sObj;
}
I am trying to add validation, specifically text validation, for my google form text items.
However, it looks to me like the 'setValidation()' function only works with items with known type like TextItem.
To my understanding, if I pull a form item via 'getItemById()', I would get a generic item. It still has 'TEXT' type but google script just doesn't see it as a TextItem and therefore the 'setValidation()' function is not available for it.
I have tried doing thing like .asTextItem() with no luck. Here is an example script that fails to run because of an error
'TypeError: Cannot find function setValidation in object Item. (line
10, file "Code")' on line 9.
function validationTest() {
var form = FormApp.getActiveForm();
var items = form.getItems();
var textValidation = FormApp.createTextValidation()
.requireNumberGreaterThanOrEqualTo(0)
.requireWholeNumber();
for (var i = 0; i<items.length; i++) {
items[i].asTextItem();
items[i].setValidation(textValidation);
};
}
So, is there a known solution or workaround for this issue? Thank you in advance.
SC
You should add .build() at the end of your validation builder, as it's shown here.
Also, asTextItem should be called simultaneously with setValidation:
function validationTest() {
var form = FormApp.getActiveForm();
var items = form.getItems();
var textValidation = FormApp.createTextValidation()
.requireNumberGreaterThanOrEqualTo(0)
.requireWholeNumber()
.build();
for (var i = 0; i<items.length; i++) {
items[i].asTextItem().setValidation(textValidation);
};
}
I am very new to Google Apps Scripts and am curious how I can use functions created in my own project. For example, I have a script bound to a spreadsheet with just one function:
function addOrder(title, content) {
var sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow([ Date(), title, content]);
}
It simply takes 2 arguments and adds a row to the spreadsheet with that data. I have deployed it as a web app, but I'm not sure how to use this function in an environment like JSFiddle. Any help is appreciated.
Thanks
Spreadsheet bound scripts run server side and the SpreadsheetApp.getActiveSheet() method you are using will only work in the context of a spreadsheet bound script since it's the only case where the script actually "sees" an active spreadsheet. When you deploy this as a webapp you will have to tell the script which spreadsheet it must look at using for example the SpreadsheetApp.openById('spreadsheet ID') method.
But even doing so will not allow for using such a code outside of Google environment (as in JS fiddle for example) since SpreadsheetApp is specific to Google Apps service.
You have to remember that Google Apps Script is based on JavaScript but is not "plain" JavaScript , it uses a lot of specific services that work only in relation with Google Apps.
edit to answer your comment below :
the code used in the spreadsheet to work as a data server goes like this : (this is deployed as a webapp without user interface. It runs as a service
function doGet(e) {
if(e.parameter.mode==null){return ContentService.createTextOutput("error, wrong request").setMimeType(ContentService.MimeType.TEXT)};
var mode = e.parameter.mode;
var value = e.parameter.value;
var ss = SpreadsheetApp.openById('1yad5sZZt-X6bIftpR--OSyf3VZWf3Jxx8UJBhh7Arwg');
var sh = ss.getSheets()[0];
if(mode=='read'){
var sheetValues = sh.getDataRange().getValues();// get data from sheet
var valToReturn = ContentService.createTextOutput(JSON.stringify(sheetValues)).setMimeType(ContentService.MimeType.JSON);
return valToReturn;// send it as JSon string
}
if(mode=='write'){
var val = Utilities.base64Decode(value,Utilities.Charset.UTF_8);// decode base64 and get an array of numbers
Logger.log(val);// see it !
var stringVal = ''; // create an empty string
for(var n in val){
stringVal += String.fromCharCode(val[n]);// add each character in turn
}
var sheetValues = JSON.parse(stringVal);// convert the string into an object (2D array)
Logger.log(sheetValues);// check result
sh.getRange(1,1,sheetValues.length,sheetValues[0].length).setValues(sheetValues);// update the sheet
return ContentService.createTextOutput(JSON.stringify(sheetValues)).setMimeType(ContentService.MimeType.JSON);// send back the result as a string
}
return ContentService.createTextOutput('error').setMimeType(ContentService.MimeType.TEXT);// in case mode is not 'read' nor 'write'... should not happen !
}
you can call this service by its url + parameters and it will get / set values in the spreadsheet. This is a basic example but it works nicely.
below it the webapp code of the Ui that uses this service in this spreadsheet
var stylePanel = {'padding':'50px', 'background':'#FFA'};
var styleButton = {'padding':'5px', 'border-radius':'5px', 'borderWidth':'1px', 'borderColor':'#DDD','fontSize':'12pt'};
var styleTextItalic = {'fontSize':'12pt','fontStyle':'italic','fontFamily':'arial,sans-serif','color':'#F00'};
var styleTextNormal = {'fontSize':'12pt','fontStyle':'normal','fontFamily':'arial,sans-serif','color':'#00F'};
var styleLabel = {'fontSize':'12pt','color':'#F00'};
var url = 'https://script.google.com/macros/s/AKfycbwPioVjYMSrmhKnJOaF2GG83dnstLWI7isU9SF1vxPV8td-g9E7/exec';
var numRow = 21;// the number of rows in the grid = number of rows in the SS + 1
;
function doGet() {
var app = UiApp.createApplication().setTitle('url_fetch_demo');
var panel = app.createVerticalPanel().setStyleAttributes(stylePanel);
var headers = ['Field Name','Your answer'];// grid title
var grid = app.createGrid(numRow+2,2);// create the grid with right size
var wait = app.createImage('https://dl.dropboxusercontent.com/u/211279/loading3T.gif').setId('wait').setVisible(false);// get a spinner image in animated gif
var handlerWrite = app.createServerHandler('writeSheet').addCallbackElement(grid);// 2 handlers for the buttons
var handlerRead = app.createServerHandler('readSheet').addCallbackElement(grid);
var Chandler = app.createClientHandler().forTargets(wait).setVisible(true);// a client handler for the spinner
var buttonWrite = app.createButton('Write to Sheet',handlerWrite).addClickHandler(Chandler).setStyleAttributes(styleButton);
var buttonRead = app.createButton('Read from Sheet',handlerRead).addClickHandler(Chandler).setStyleAttributes(styleButton);
for(var n=1 ; n < numRow ; n++){
for(var m=0 ; m < 2 ; m++){ // create all the textBoxes with names & IDs
var textBox = app.createTextBox().setText('no value').setName('text'+n+'-'+m).setId('text'+n+'-'+m).setStyleAttributes(styleTextNormal);
//if(m==0){textBox.setEnabled(false)};// prevent writing to left column (optional)
grid.setWidget(n,m,textBox);// place widgets
}
}
grid.setWidget(numRow,0,buttonRead).setWidget(numRow,1,buttonWrite).setWidget(numRow+1,1,wait) // place buttons
.setWidget(0,0,app.createLabel(headers[0]).setStyleAttributes(styleLabel)) // and headers
.setWidget(0,1,app.createLabel(headers[1]).setStyleAttributes(styleLabel));
app.add(panel.add(grid));
return app; // show Ui
}
function writeSheet(e){
var app = UiApp.getActiveApplication();
app.getElementById('wait').setVisible(false);// spinner will be hidden when fct returns
var dataArrayImage = [];// an array to get typed values
for(var n=1 ; n < numRow ; n++){
var row=[];
for(var m=0 ; m < 2 ; m++){
row.push(e.parameter['text'+n+'-'+m]); // get every value in every "cell"
var textBox = app.getElementById('text'+n+'-'+m).setStyleAttributes(styleTextItalic);// update "cells" style
//textBox.setText('written value = '+e.parameter['text'+n+'-'+m]);// rewrite to the cells - not usefull but serves to check while debugging
}
dataArrayImage.push(row);// store one row(=2cells)
}
var UiValues = JSON.stringify(dataArrayImage);// stringfy the array
var newValues = url+'?mode=write&value='+Utilities.base64Encode(UiValues,Utilities.Charset.UTF_8);// add to url & parameters+ encode in pure ASCII characters
Logger.log(newValues);// check in logger
var check = UrlFetchApp.fetch(newValues).getContent();// get back the result
Logger.log(check);// check result = newValues sent back in bytes format
return app;//update Ui
}
function readSheet(e){
var app = UiApp.getActiveApplication();
app.getElementById('wait').setVisible(false);
var returnedValue = UrlFetchApp.fetch(url+'?mode=read').getContentText();// get data from server
Logger.log(returnedValue);// check values
var sheetValues = JSON.parse(returnedValue);
for(var n=1 ; n < numRow ; n++){
for(var m=0 ; m < 2 ; m++){
var textBox = app.getElementById('text'+n+'-'+m).setStyleAttributes(styleTextNormal);
textBox.setText(sheetValues[n-1][m]);// iterate and update cells values
}
}
return app;// update Ui
}