Is there a way to speed up this for loop in Google Script? - for-loop

I have a for loop which is working on my google sheet but it takes around 5 minutes to filter through the 2100 rows of data. I have read about using filters and getting rid of the for loop all together but I'm fairly new to coding in Google Script and haven't been able to get my head around the syntax for this. Any advice greatly appreciated.
Code below:
function Inspect() {a
var sSheet = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = sSheet.getSheetByName("Inventory");
var tarSheet = sSheet.getSheetByName("Inspections");
var lastRow = srcSheet.getLastRow();
for (var i = 2; i <= lastRow; i++) {
var cell = srcSheet.getRange("A" + i);
var val = cell.getValue();
if (val == true) {
var srcRange = srcSheet.getRange("B" + i + ":I" + i);
var clrRange = srcSheet.getRange("A" + i);
var tarRow = tarSheet.getLastRow();
tarSheet.insertRowAfter(tarRow);
var tarRange = tarSheet.getRange("A" + (tarRow+1) + ":H" + (tarRow+1));
var now = new Date();
var timeRange = tarSheet.getRange("I"+(tarRow+1));
timeRange.setValue(now);
srcRange.copyTo(tarRange);
clrRange.clear();
//tarRange.activate();
timeRange.offset(0, 1).activate();
}
}
};

Yes, to speed-up you will need to get all the values first and apply your logic to the obtained 2D-arrays instead of cells, at the end you will use setValues to update your sheet. I would go for something like this:
function Inspect() {
var sSheet = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = sSheet.getSheetByName("Inventory");
var tarSheet = sSheet.getSheetByName("Inspections");
var srcLastRow = srcSheet.getLastRow();
var tarLastRow = tarSheet.getLastRow();
var srcArray = srcSheet.getRange(1,1,srcLastRow,9).getValues();//(A1:I(lastrow))
var tarArray = tarSheet.getRange(1,1,tarLastRow,9).getValues();//(A1:I(lastrow))
for (var i = 1; i < srcArray.length; i++) {
var val = srcArray[i][0];
if (val == true) {
var copyValues = srcArray[i].slice(1);//Get all elements from the row excluding first column (srcSheet.getRange("B" + i + ":I" + i);)
var now = new Date();
copyValues[8]=now;//set the time on column 9 (array starts at position 0!)
var tarNewLine = copyValues;
tarArray.push(tarNewLine);
//clear values on source (except column A):
for(var j=1;j<srcArray[i].length;j++){
srcArray[i][j]="";
}
}
}
tarSheet.clear();
tarSheet.getRange(1, 1,tarArray.length,tarArray[0].length).setValues(tarArray);
srcSheet.clear();
srcSheet.getRange(1, 1,srcArray.length,srcArray[0].length).setValues(srcArray);
};

You cannot get around a loop, but you should reduce the number of calls to the SpreadsheetApp to a minimum, see Apps Script Best Practices
It is not the for loop, but those calls that make your code slow. Instead, work with arrays as much as you can. Loops become of a problem if they are nested - this is also something you should avoid.
Sample how to perform most calls to SpreadsheetApp outside of the loop and work with arrays:
function Inspect() {
var sSheet = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = sSheet.getSheetByName("Inventory");
var tarSheet = sSheet.getSheetByName("Inspections");
var lastRow = srcSheet.getLastRow();
var Acolumn = srcSheet.getRange("A2:A" + lastRow);
var Avalues = Acolumn.getValues();
var srcRange = srcSheet.getRange("B2:I" + lastRow);
var srcValues = srcRange.getValues();
var array = [];
var now = new Date();
for (var i = 0; i < lastRow-1; i++) {
var val = Avalues[i][0];
if (val == true) {
srcValues[i].push(now);
array.push(srcValues[i]);
var clrRange = Acolumn.getCell(i+1, 1);
clrRange.clear();
}
}
var tarRow = tarSheet.getLastRow();
tarSheet.insertRowAfter(tarRow);
if(array.length!=0){
var tarRange = tarSheet.getRange("A" + (tarRow+1) + ":I" + (tarRow + array.length));
tarRange.setValues(array);
}
};

Related

Returning certain rows which meet a criteria - Google Apps Script

What I am trying to do is: I have a list, with N being a date and O being a checkbox. I need to get the rows which =N < Today() && O=False, then return A:B of those corresponding rows. I've tried it every which way, and I can't get it to work. Any suggestions?
function msg1(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var wscl = ss.getSheetByName('Connection List');
var contact = wscl.getRange("A2:B").getValues();
var msg1date = wscl.getRange("N2:N").getValues();
var msg1sent = wscl.getRange("O2:O").getValues();
var MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
var now = new Date();
var yesterday = new Date(now.getTime() - MILLIS_PER_DAY);
for(var i=0;i<msg1sent.length;i++){
if(msg1sent =="FALSE"&& msg1date < yesterday){
var row=i+1;
}
}
}
If you use getValues() of a checkbox it returns true or false booleans. If you use getDisplayValues() it returns "TRUE" or "FALSE" strings. And for the dates I just used valueOf() but you can also use getTime(). The easiest way to figure all of this out is to create some intermediate temporary variables and view them in the Script Debugger and you can see all of the return values there.
function msg1(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Connection List');
var ct=sh.getRange(2,1,sh.getLastRow()-1,2).getValues();
var date=sh.getRange(2,14,sh.getLastRow()-1,1).getValues();//date
var sent=sh.getRange(2,15,sh.getLastRow()-1,1).getValues();//checkbox
var dt=new Date();
var rows=[];
var today=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()).valueOf();//0000 or midnight
for(var i=0;i<sent.length;i++){
var t1=sent[i][0];
var t2=new Date(date[i][0]).valueOf();
var t3=today;
if(sent[i][0]==false && new Date(date[i][0]).valueOf()<today){
rows.push(ct[i]);
}
}
Logger.log(rows);
}
If you use getDisplayValues() then it would look like this:
function msg1(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Connection List');
var ct=sh.getRange(2,1,sh.getLastRow()-1,2).getValues();
var date=sh.getRange(2,14,sh.getLastRow()-1,1).getValues();//date
var sent=sh.getRange(2,15,sh.getLastRow()-1,1).getDisplayValues();//checkbox
var dt=new Date();
var rows=[];
var today=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()).valueOf();
for(var i=0;i<sent.length;i++){
var t1=sent[i][0];
var t2=new Date(date[i][0]).valueOf();
var t3=today;
if(sent[i][0]=="FALSE" && new Date(date[i][0]).valueOf()<today){
rows.push(ct[i]);
}
}
Logger.log(rows);
}

I have a google script that creates QR codes and Barcode. the QR Codes show up twice. Once where its suppose to and then at the end of the document

The code below generates a label that has a QR Code and barcode. Currently I am trying to get both to work. They both show up in the label but when it does the QR code will be added in the correct spot but also will add extra qr codes on the last label generated. The two qr codes at the end are itemnum qr codes and they are not suppose to be there. It normally puts them ontop of each other i moved them so people could see. The barcodes generate just fine but they don't scan
TEST SCRIPT here is a link to test it.. This is a test script and not part of a business so its easy to do. Basically what needs done is click on My Custom Menu and select reset labels. Once the labels are created you can go to the labels tab and select a few labels with serial numbers then go back to the menu and select create labels for selected items.
//####################################### Create Zebra Label #########################
function createZebraLabel(monthlySheet, newSheetName) {
var parentFolder = DriveApp.getFolderById('1mUPLw1PSi-guH19uJPCPWmogkpdckLcW');
var createdoc = DocumentApp.create('Zebra Label').getId();
doc = DocumentApp.openById(createdoc);
var id = createdoc;
var docFile = DriveApp.getFileById(doc.getId());
var target = parentFolder;
var file1 = DriveApp.getFileById(id);
var mkfile1 = file1.makeCopy(newSheetName, target).getId();
doc = DocumentApp.openById(mkfile1);
docFile.setTrashed(true);
//325
var body = doc.getBody().setPageWidth(325).setPageHeight(180).setMarginTop(.2).setMarginBottom(.2);
// var body = doc.getBody().setPageWidth(144).setPageHeight(144).setMarginTop(.2).setMarginBottom(.2);
var sourceSpreadSheet = SpreadsheetApp.openById(monthlySheet);
var ss = sourceSpreadSheet.getSheetByName('Sheet1');
var startRow = 1; // First row of data to process
var numRows = 250; // Number of rows to process
var startColumn = 1; // A=1 B=2
var numColumns = 5; // Number of columns to process
var dataRange = ss.getRange(startRow, startColumn, numRows, numColumns);
var data = dataRange.getValues();
for (var i = 1; i < data.length; ++i) {
var row = data[i];
var actualrow = i;
var itemnum = row[0]; // A column
var desc = row[1]; // B column
var serial = row[2]; // D column
var bin = row[3]; // D column
var qty = row[4];
var styleLeft = {};
styleLeft[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT;
styleLeft[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
styleLeft[DocumentApp.Attribute.FONT_SIZE] = 14;
styleLeft[DocumentApp.Attribute.BOLD] = true;
var styleRight = {};
styleRight[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.RIGHT;
styleRight[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
styleRight[DocumentApp.Attribute.FONT_SIZE] = 14;
styleRight[DocumentApp.Attribute.BOLD] = true;
var itemBarcode = {};
itemBarcode[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT;
itemBarcode[DocumentApp.Attribute.FONT_FAMILY] = 'Libre Barcode 39 Extended Text';
itemBarcode[DocumentApp.Attribute.FONT_SIZE] = 25;
itemBarcode[DocumentApp.Attribute.BOLD] = false;
var serialBarcode = {};
serialBarcode[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.CENTER;
serialBarcode[DocumentApp.Attribute.FONT_FAMILY] = 'Libre Barcode 39 Extended Text';
serialBarcode[DocumentApp.Attribute.FONT_SIZE] = 20;
serialBarcode[DocumentApp.Attribute.BOLD] = false;
var nospace = {};
nospace[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.RIGHT;
nospace[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
nospace[DocumentApp.Attribute.FONT_SIZE] = 1;
nospace[DocumentApp.Attribute.BOLD] = true;
var text = body.editAsText();
var itemqrcode = UrlFetchApp.fetch('https://chart.googleapis.com/chart?chs=70x70&cht=qr&chl=' + itemnum);
var serialqrcode = UrlFetchApp.fetch('https://chart.googleapis.com/chart?chs=70x70&cht=qr&chl=' + serial);
if (itemnum != '') {
//#################### SERIAL ###################
if (serial != '') { // SERIAL NUMBER
body.appendParagraph('').setAttributes(nospace);
var paragraph = body.appendParagraph('Item Number: ' + itemnum).setAttributes(styleLeft);
paragraph.addPositionedImage(itemqrcode.getBlob()).setLayout(DocumentApp.PositionedLayout.WRAP_TEXT)
body.appendParagraph('*' + itemnum + '*').setAttributes(itemBarcode);
body.appendParagraph('\n\n').setAttributes(nospace).appendHorizontalRule();
//description
body.appendParagraph(desc).setAttributes(styleLeft);
body.appendParagraph('').setAttributes(nospace);
//serials
body.appendParagraph('').setAttributes(nospace).appendHorizontalRule();
var paragraph = body.appendParagraph('Serial Number: ' + serial).setAttributes(styleRight);
body.appendParagraph('*' + serial + '*').setAttributes(serialBarcode);
paragraph.addPositionedImage(serialqrcode.getBlob()).setLayout(DocumentApp.PositionedLayout.WRAP_TEXT)
body.appendParagraph('').setAttributes(nospace);
} else if (serial == '') { // NO SERIAL NUMBER
var styleCenter = {};
styleCenter[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.CENTER;
styleCenter[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
styleCenter[DocumentApp.Attribute.FONT_SIZE] = 18;
styleCenter[DocumentApp.Attribute.BOLD] = true;
var itemBarcode = {};
itemBarcode[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.CENTER;
itemBarcode[DocumentApp.Attribute.FONT_FAMILY] = 'Libre Barcode 39 Extended Text';
itemBarcode[DocumentApp.Attribute.FONT_SIZE] = 35;
itemBarcode[DocumentApp.Attribute.BOLD] = false;
var styleLocation = {};
styleLocation[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT;
styleLocation[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
styleLocation[DocumentApp.Attribute.FONT_SIZE] = 12;
styleLocation[DocumentApp.Attribute.BOLD] = true;
body.appendParagraph('').setAttributes(nospace);
var paragraph = body.appendParagraph('Item Number: ' + itemnum).setAttributes(styleLeft);
body.appendParagraph('*' + itemnum + '*').setAttributes(itemBarcode);
body.appendParagraph('\n').setAttributes(nospace).appendHorizontalRule();
//description
body.appendParagraph(desc).setAttributes(styleLeft);
body.appendParagraph('').setAttributes(nospace).appendHorizontalRule();
body.appendParagraph('Location: ' + bin + ' Qty: ' + qty).setAttributes(styleLocation);
body.appendParagraph('\n').setAttributes(nospace);
}
body.appendPageBreak();
}
}
var googledoc = doc.getUrl();
FinishedGoogleDoc(googledoc);
}
Below is my solution that does work.
/
/####################################### Create Zebra Label #########################
function createZebraLabel(monthlySheet,newSheetName){
var parentFolder=DriveApp.getFolderById('1mUPLw1PSi-guH19uJPCPWmogkpdckLcW');
var createdoc = DocumentApp.create('Zebra Label').getId();
doc = DocumentApp.openById(createdoc);
var id = createdoc;
var docFile = DriveApp.getFileById(doc.getId());
var target = parentFolder;
var file1 = DriveApp.getFileById(id);
var mkfile1 = file1.makeCopy(newSheetName, target).getId();
doc = DocumentApp.openById(mkfile1);
docFile.setTrashed(true);
//325
var body = doc.getBody().setPageWidth(325).setPageHeight(180).setMarginTop(.02).setMarginBottom(.02);
// var body = doc.getBody().setPageWidth(144).setPageHeight(200).setMarginTop(.01).setMarginBottom(.01);
var sourceSpreadSheet = SpreadsheetApp.openById(monthlySheet);
var ss = sourceSpreadSheet.getSheetByName('Sheet1');
var startRow = 1; // First row of data to process
var numRows = 250; // Number of rows to process
var startColumn = 1; // A=1 B=2
var numColumns = 5; // Number of columns to process
var dataRange = ss.getRange(startRow, startColumn, numRows, numColumns);
var data = dataRange.getValues();
for (var i = 1; i < data.length; ++i) {
var row = data[i];
var actualrow=i;
var itemnum = row[0]; // A column
var desc = row[1]; // B column
var serial = row[2]; // D column
var bin = row[3]; // D column
var qty =row[4];
if (itemnum != ''){
var styleITEMNUM = {};
styleITEMNUM[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.RIGHT;
styleITEMNUM[DocumentApp.Attribute.VERTICAL_ALIGNMENT] =DocumentApp.VerticalAlignment.CENTER;
styleITEMNUM[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
styleITEMNUM[DocumentApp.Attribute.FONT_SIZE] = 14;
styleITEMNUM[DocumentApp.Attribute.BOLD] = true;
var styleDESC = {};
styleDESC[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT;
styleDESC[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
styleDESC[DocumentApp.Attribute.FONT_SIZE] = 10;
styleDESC[DocumentApp.Attribute.BOLD] = true;
var styleSERIAL = {};
styleSERIAL[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.RIGHT;
styleSERIAL[DocumentApp.Attribute.VERTICAL_ALIGNMENT] =DocumentApp.VerticalAlignment.CENTER;
styleSERIAL[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
styleSERIAL[DocumentApp.Attribute.FONT_SIZE] = 12;
styleSERIAL[DocumentApp.Attribute.BOLD] = true;
var nospace = {};
nospace[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.RIGHT;
nospace[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
nospace[DocumentApp.Attribute.FONT_SIZE] =-1;
nospace[DocumentApp.Attribute.BOLD] = true;
var text = body.editAsText();
var paraStyle = {};
paraStyle[DocumentApp.Attribute.PADDING_BOTTOM] = 0;
paraStyle[DocumentApp.Attribute.PADDING_TOP] = 0;
paraStyle[DocumentApp.Attribute.MARGIN_TOP] = 0;
paraStyle[DocumentApp.Attribute.SPACING_BEFORE] = 0;
paraStyle[DocumentApp.Attribute.SPACING_AFTER] = 0;
paraStyle[DocumentApp.Attribute.LINE_SPACING] = 0;
var itemqrcode = UrlFetchApp.fetch('https://chart.googleapis.com/chart?chs=80x80&cht=qr&chl='+itemnum);
var serialqrcode = UrlFetchApp.fetch('https://chart.googleapis.com/chart?chs=80x80&cht=qr&chl='+serial);
//#################### ITEM WITH SERIAL NUMBER ###################
if (itemnum != '' && serial != ''){ // SERIAL NUMBE
body.appendParagraph('').setAttributes(nospace);
var table = body.appendTable().setBorderWidth(0).setAttributes(paraStyle);
var tr = table.appendTableRow().setAttributes(paraStyle);
var td = tr.appendTableCell('').setWidth(80).setPaddingTop(0).setPaddingBottom(0).appendImage(itemqrcode.getBlob()).setAttributes(paraStyle);
var td = tr.appendTableCell('Item Number\n' +itemnum).setPaddingTop(0).setPaddingBottom(0).setAttributes(styleITEMNUM);
body.appendHorizontalRule().setAttributes(nospace);
body.appendParagraph(desc).setAttributes(styleDESC);
body.appendParagraph('').setAttributes(nospace).appendHorizontalRule().setAttributes(nospace);
body.appendParagraph('').setAttributes(nospace);
var table = body.appendTable().setBorderWidth(0).setAttributes(paraStyle);
var tr = table.appendTableRow().setAttributes(paraStyle);
var td = tr.appendTableCell('').setWidth(80).setPaddingTop(0).setPaddingBottom(0).appendImage(serialqrcode.getBlob()).setHeight(80);
var td = tr.appendTableCell('Serial Number\n ' +serial).setPaddingTop(0).setPaddingBottom(0).setAttributes(styleSERIAL);
}
else if (itemnum != '' && serial == ''){ // NO SERIAL NUMBER
var styleLocation = {};
styleLocation[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT;
styleLocation[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
styleLocation[DocumentApp.Attribute.FONT_SIZE] =12;
styleLocation[DocumentApp.Attribute.BOLD] = true;
body.appendParagraph('').setAttributes(nospace);
var table = body.appendTable().setBorderWidth(0).setAttributes(paraStyle);
var tr = table.appendTableRow().setAttributes(paraStyle);
var td = tr.appendTableCell('').setWidth(80).setPaddingTop(0).setPaddingBottom(0).appendImage(itemqrcode.getBlob()).setAttributes(paraStyle);
var td=tr.appendTableCell('Item Number\n' +itemnum).setAttributes(styleITEMNUM);
body.appendParagraph('\n').setAttributes(nospace).appendHorizontalRule();
body.appendParagraph(desc).setAttributes(styleDESC);
body.appendParagraph('\n').setAttributes(nospace).appendHorizontalRule();
body.appendParagraph('').setAttributes(nospace);
var table = body.appendTable().setBorderWidth(0).setAttributes(paraStyle);
var tr = table.appendTableRow().setAttributes(paraStyle);
var td=tr.appendTableCell('Location:'+bin).setWidth(200).setPaddingTop(0).setPaddingBottom(0).setAttributes(styleLocation);
var td=tr.appendTableCell('Qty: ' +qty).setAttributes(styleLocation);
}
body.appendPageBreak();
}
}
var googledoc = doc.getUrl();
FinishedGoogleDoc(googledoc);
}

Enhancing Performance in Student Info App

I've built a simple Student Information platform using Google Sheets. It allows the user to query, update and create new student info on a user interface. Please refer to this sheet to see how it works.
The functions to Refresh/Update/Save are inside the Actions button on a menu bar. Everything seems to work well however when the number of records increases, say above 100 records, all the functions slow down and it gets extremely slow with 200+ records.
Appreciate if anyone could help to take a look at the scripts as I suspect they need to be optimized.
Many thanks in advance!
function UpdateDataIntoMaster() { //This script is used in the SAVE button in UPDATE sheet)
/*Get data from UPDATE Sheet*/
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY");
var sheet = ss.getSheetByName('UPDATE');
var range = sheet.getRange("D30:AE30"); //All data transposed into this line. MUST be updated if more fields are added into the Data sheet
var values = range.getValues();
var rangeForKey = sheet.getRange("D30") //Student Name is used as the
key identifier
var keyValue = rangeForKey.getValue();
/*Pass in keyValue(identifier = Student Name)
and all data in the function below in order
to update master data sheet*/
updDbase(keyValue,values);
function updDbase(keyValue,values) {
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY")
var sheet = ss.getSheetByName('Data');
var data = sheet.getDataRange().getValues();
var noOfRow = values.length
var noOfCol = values[0].length
for (var i=0; i < data.length; i++) { // going through all the rows in Data sheet
var keyData = ss.getSheetByName("Data").getRange(i+1,1).getValue(); //Get the Student Name from Data sheet
if (keyData == keyValue) {
// for (var j=0; j < data[i].length; j++) { // this is going through all the cell of a row
var row = Number(i)+1;
var sh = SpreadsheetApp.getUi();
var response = sh.alert("Update Information","Are you sure you want to update the student information?", sh.ButtonSet.YES_NO);
if (response == sh.Button.YES)
{
var sheets = ss.getSheetByName("Data").getRange(row,1,noOfRow,noOfCol).setValues(values);
}//If response == YES
}
}
}
}
function CreateNew() {
/*Get data from Inquiry Sheet*/
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY");
var sheetNew = ss.getSheetByName('Create New');
var range = sheetNew.getRange("D30:AZE30"); //All data transposed into
this line
var values = range.getValues();
var rangeForKey = sheetNew.getRange("E30") //Using Student ID as key identifier
var keyValue = rangeForKey.getValue();
var noOfRow = values.length
var noOfCol = values[0].length
var sheetData = ss.getSheetByName('Data');
var lastRow = sheetData.getLastRow();
var data = sheetData.getDataRange().getValues();
for (var i=0; i < data.length; i++) { // going through all the rows in Data sheet
var keyData = sheetData.getRange(i+1,2).getValue(); //Get the Student ID from Data sheet
if (keyData == keyValue) {
AlertBox();//If Student ID is found, to prompt Student ID already
exist
return;
} //If
} //For
/*Confirming with user whether to proceed to create new entry*/
var sh = SpreadsheetApp.getUi();
var response = sh.alert("Create New Record","Are you sure you want to
create new student information?", sh.ButtonSet.YES_NO);
if (response == sh.Button.YES){
if (keyValue == ""){
var response = sh.alert("Create New Record","Unable to proceed
because Student ID is empty", sh.ButtonSet.OK);
return;}
else {
//var response = sh.alert("Create New Record","Unable to
proceed because Student ID is empty", sh.ButtonSet.OK);
var sheets =
sheetData.getRange(lastRow+1,1,1,noOfCol).setValues(values)
}
}//If
}
function EditStudentInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Inquiry");
//var ss = SpreadsheetApp.getActive();
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
}
function EditContent() {
var s = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Update");
var rangeContentCol1 = s.getRange("E3:E23");
var CopyContentCol1 = s.getRange("E3:E23").getValues();
var rangeContentCol2 = s.getRange("I3:I23");
var CopyContentCol2 = s.getRange("I3:I23").getValues();
rangeContentCol1.clearContent();
rangeContentCol2.clearContent();
var PasteContentCol1 =
s.getRange("E3:E23").setValues(CopyContentCol1);
var PasteContentCol2 = s.getRange("I3:I23").setValues(CopyContentCol2);
}
A common performance mistake people with Apps Script is doing the .getRange().getValues() within their for loops. Performance-wise these get and set calls are quite expensive.
Lucky the fix for this is quite easy - get all the data at once first, then loops through it. You actually do this already, sort of. In your script you get the whole data range, but then only use a part of the data and instead do another getValues call. I've updated the two areas in your script that had getRange() calls in a for loop --> var keyData = data[i][0];
function UpdateDataIntoMaster() { //This script is used in the SAVE button in UPDATE sheet)
/*Get data from UPDATE Sheet*/
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY");
var sheet = ss.getSheetByName('UPDATE');
var range = sheet.getRange("D30:AE30"); //All data transposed into this line. MUST be updated if more fields are added into the Data sheet
var values = range.getValues();
var rangeForKey = sheet.getRange("D30") //Student Name is used as the
key identifier
var keyValue = rangeForKey.getValue();
/*Pass in keyValue(identifier = Student Name)
and all data in the function below in order
to update master data sheet*/
updDbase(keyValue,values);
function updDbase(keyValue,values) {
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY")
var sheet = ss.getSheetByName('Data');
var data = sheet.getDataRange().getValues();
var noOfRow = values.length
var noOfCol = values[0].length
for (var i=0; i < data.length; i++) { // going through all the rows in Data sheet
var keyData = data[i][0]; //Use the data that is already loaded.
if (keyData == keyValue) {
// for (var j=0; j < data[i].length; j++) { // this is going through all the cell of a row
var row = Number(i)+1;
var sh = SpreadsheetApp.getUi();
var response = sh.alert("Update Information","Are you sure you want to update the student information?", sh.ButtonSet.YES_NO);
if (response == sh.Button.YES)
{
var sheets = ss.getSheetByName("Data").getRange(row,1,noOfRow,noOfCol).setValues(values);
}//If response == YES
}
}
}
}
function CreateNew() {
/*Get data from Inquiry Sheet*/
var ss = SpreadsheetApp.openById("11Djp9UmXbtWv7VitZFfo0X4Ctet3O8Amh4xADNKOZgY");
var sheetNew = ss.getSheetByName('Create New');
var range = sheetNew.getRange("D30:AZE30"); //All data transposed into
this line
var values = range.getValues();
var rangeForKey = sheetNew.getRange("E30") //Using Student ID as key identifier
var keyValue = rangeForKey.getValue();
var noOfRow = values.length
var noOfCol = values[0].length
var sheetData = ss.getSheetByName('Data');
var lastRow = sheetData.getLastRow();
var data = sheetData.getDataRange().getValues();
for (var i=0; i < data.length; i++) { // going through all the rows in Data sheet
var keyData = data[i][0]; //Use the data that is already loaded.
if (keyData == keyValue) {
AlertBox();//If Student ID is found, to prompt Student ID already
exist
return;
} //If
} //For
/*Confirming with user whether to proceed to create new entry*/
var sh = SpreadsheetApp.getUi();
var response = sh.alert("Create New Record","Are you sure you want to
create new student information?", sh.ButtonSet.YES_NO);
if (response == sh.Button.YES){
if (keyValue == ""){
var response = sh.alert("Create New Record","Unable to proceed
because Student ID is empty", sh.ButtonSet.OK);
return;}
else {
//var response = sh.alert("Create New Record","Unable to
proceed because Student ID is empty", sh.ButtonSet.OK);
var sheets =
sheetData.getRange(lastRow+1,1,1,noOfCol).setValues(values)
}
}//If
}
function EditStudentInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Inquiry");
//var ss = SpreadsheetApp.getActive();
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
}
function EditContent() {
var s = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Update");
var rangeContentCol1 = s.getRange("E3:E23");
var CopyContentCol1 = s.getRange("E3:E23").getValues();
var rangeContentCol2 = s.getRange("I3:I23");
var CopyContentCol2 = s.getRange("I3:I23").getValues();
rangeContentCol1.clearContent();
rangeContentCol2.clearContent();
var PasteContentCol1 =
s.getRange("E3:E23").setValues(CopyContentCol1);
var PasteContentCol2 = s.getRange("I3:I23").setValues(CopyContentCol2);
}
Give this a test and let me know if it helps!

Third Listbox populate from first 2 Listboxes e.parameter [GAS]

I'm having a similar issue to this question - however I am requiring to get 2 e.parameters of both 1st and 2nd list boxes in order to populate the spreadsheet for the 3rd list box.
The vert is being read by the e.parameter, but the chan is undefined, which I do not understand as it is fully functional in the second list box but not the third.
Is there something that I have overseen in this code?
var channelBox = app.createListBox().setId('channelBox').setName('channelBox').setWidth(152).setHeight(22);
var chanHandler = app.createServerChangeHandler('showChannelinfo');
chanHandler.addCallbackElement(channelBox);
channelBox.addChangeHandler(chanHandler);
var chaArray = ['Select channel','--','Email','Phone','Chat']; for (var i=0;i<chaArray.length;++i) {channelBox.addItem(chaArray[i]);};
var verticalBox = app.createListBox().setId('verticalBox').setName('verticalBox').setWidth(152).setHeight(22);
var vertHandler = app.createServerChangeHandler('showVerticalinfo');
vertHandler.addCallbackElement(verticalBox);
verticalBox.addChangeHandler(vertHandler);
function showChannelinfo(e){
var app = UiApp.getActiveApplication();
var itemSpreadsheetKey = 'ABC------------123';
var openedSS = SpreadsheetApp.openById(itemSpreadsheetKey);
var sheetList3 = openedSS.getSheetByName("boolean3");//Vertical Lookup Sheet
var channelBox = app.getElementById('channelBox');
var verticalBox = app.getElementById('verticalBox');
var chan = e.parameter.channelBox;
if (chan == 'Phone')
{ verticalBox.clear();
var marketFilter = sheetList3.getRange('A1').setFormula('=iferror(filter(boolean2!A:D,boolean2!B:B=TRUE))');}
if (chan == 'Email')
{ verticalBox.clear();
var marketFilter = sheetList3.getRange('A1').setFormula('=iferror(filter(boolean2!A:D,boolean2!D:D=TRUE))');}
if (chan == 'Chat')
{ verticalBox.clear();
var marketFilter = sheetList3.getRange('A1').setFormula('=iferror(filter(boolean2!A:D,boolean2!C:C=TRUE))');}
var numItemList1 = sheetList3.getLastRow();//get the item array
var list1ItemArray = sheetList3.getRange(1,1,numItemList1).getValues();//Add the items in ListBox
for(var i=0; i<list1ItemArray.length; i++)
{verticalBox.addItem(list1ItemArray[i][0]);}
if (chan == '--')
{verticalBox.clear();
var vertArray = ['Select vertical','Hardware','Apps','Ebooks','Movies','Music','Nik','Shopping','Places','Wallet','YouTube','BeatThatQuote'];
for (var i=0;i<vertArray.length;++i) {verticalBox.addItem(vertArray[i]);};}
return app
};
function showVerticalinfo(e){
var app = UiApp.getActiveApplication();
var itemSpreadsheetKey = 'ABC------------123';
var openedSS = SpreadsheetApp.openById(itemSpreadsheetKey);
var sheetList4 = openedSS.getSheetByName("boolean4");//Language Lookup Sheet
var channelBox = app.getElementById('channelBox');
var verticalBox = app.getElementById('verticalBox');
var langBox = app.getElementById('langBox');
var chan = e.parameter.channelBox;
var vert = e.parameter.verticalBox;
langBox.clear();
var langFilter = sheetList4.getRange('A1').setFormula('=iferror(filter(boolean!A:D,boolean!A:A="' + chan + '",boolean!B:B="' + vert + '",boolean!D:D=TRUE))');
//**this returns as chan = undefined**
var numItemList2 = sheetList4.getLastRow();//get the item array
var list1ItemArray2 = sheetList4.getRange(1,3,numItemList2).getValues();//Add the items in ListBox
for(var i=0; i<list1ItemArray2.length; i++){langBox.addItem(list1ItemArray2[i][0]);}
if (chan == '--')
{langBox.clear();
var langArray = ['Select language','Dutch','French','German','Italian','Portuguese', 'Russian','Spanish'];
for (var i=0;i<langArray.length;++i) {langBox.addItem(langArray[i]);};}
return app
};
If anyone can use their magic eyes to give me any advice, it would be greatly appreciated!
The problem is with your callbackElement.
What I suggest is that you put both these list boxes into a single panel and add this panel as the callback element to both the handlers. Something like
function doGet(){
/* Your other code here */
var panel = app.createVerticalPanel().setId('panel');
var channelBox = app.createListBox().setId('channelBox').setName('channelBox').setWidth(152).setHeight(22);
var chanHandler = app.createServerChangeHandler('showChannelinfo');
chanHandler.addCallbackElement(panel); /* Add panel as the callback element */
channelBox.addChangeHandler(chanHandler);
var chaArray = ['Select channel','--','Email','Phone','Chat']; for (var i=0;i<chaArray.length;++i) {channelBox.addItem(chaArray[i]);};
var verticalBox = app.createListBox().setId('verticalBox').setName('verticalBox').setWidth(152).setHeight(22);
var vertHandler = app.createServerChangeHandler('showVerticalinfo');
vertHandler.addCallbackElement(panel); /* Add panel as the callback element */
verticalBox.addChangeHandler(vertHandler);
panel.add(channelBox);
panel.add(verticalBox);
/* Your other UI Code here */
}

How to set i to 0 of the first item from a json criteria

I want to set i to 0 of the first item from a json criteria, eg. if the criteria is green in this case the i will start from 3... if criteria = blue it will start on 2... i need to set it to start from 0 or 1 whether it is.. also how to count total of a criteria, eg. green total is 2,, blue=1, red=2... thanks in advance!
var myBox_html ="";
var i = 0;
function createDiv(1x,2x,3x) {
A = '<something>'+1x;
B = '<something>'+2x;
C = '<something>'+3x;
myBox_html += '<something-more>'+A+B+C;
}
criteria // is a parameter from url, in this case means green
get_it = function(doc) {
var jsonData = eval('(' + doc + ')');
for (var i=0; i<jsonvar.name.length; i++) {
var 1x = jsonvar.name[i].1;
var 2x = jsonvar.name[i].2;
var 3x = jsonvar.name[i].3;
if (1x == criteria){
var Div = createDiv(1x,2x,3x);
} else {null}
}
document.getElementById("myBox").innerHTML = myBox_html;
}
get_it();
json should look like this:
var jsonvar = {"name":[{"1":"red","2":"round","3":"fruit"},{"1":"red","2":"squared","3":"box"},{"1":"blue","2":"squared","3":"box"},{"1":"green","2":"squared","3":"box"},{"1":"green","2":"pear","3":"fruit"}]};
Consider several solutions:
1: Generate criteria-grouped JSON response on the server-side. E.g.
var jsonvar = '{"name":{
"red": [{"1":"red","2":"round","3":"fruit"}, {"1":"red","2":"squared","3":"box"}],
"blue": [{"1":"blue","2":"squared","3":"box"}],
"green":[{"1":"green","2":"squared","3":"box"}, {"1":"green","2":"pear","3":"fruit"}]}}';
2: Convert you JSON array to criteria-grouped format as defined above. Here is sample routine for such a grouping:
function group_elements (arr) {
var result = {};
for (var i=0; i < arr.length; i++) {
if (!result[arr[i][1]]) {
result[arr[i][1]] = [];
}
result[arr[i][1]].push(arr[i]);
}
return result;
}
Both solutions allows you to iterate only filtered records and count length of group.

Resources