Form Validation Before Submission - validation
I can't get my form to validate before it is submitted to my spreadsheet. Once I click submit it does nothing...
I also am not sure how to validate the Date to make sure it is in the correct format before submission. I have tried to setup the validation but before I can test it, i have to be able to submit and get validation results.
What am I doing wrong? I have included the code below:
function doGet() {
var app = UiApp.createApplication().setTitle('DHS: Kurzweil Calendar');
//Create a panel which holds all the form elelemnts
var vrtMainPanel = app.createVerticalPanel().setId('vrtMainPanel');
//Create Spreadsheet Source
var spSheet = SpreadsheetApp.openById('0Aur3owCpuUY-dFF0dVZXb3I1Yjlpbzg3SXFIaklEcUE');
var spTeacherList = spSheet.getSheetByName('TeacherList');
var spSubjectList = spSheet.getSheetByName('SubjectList');
var spPeriodList = spSheet.getSheetByName('PeriodList');
var spCountList = spSheet.getSheetByName('CountList');
//Create the form elements
var hdlTeacherName = app.createServerHandler('getTeacherName').addCallbackElement(vrtMainPanel);
var lbxTeacherName = app.createListBox().setId('lbxTeacherName').setName('lbxTeacherName').addChangeHandler(hdlTeacherName);
var lstTeacherNames = spTeacherList.getRange(1,1,spTeacherList.getLastRow(),1).getValues();
lstTeacherNames.sort();
for (var l = 0; l < lstTeacherNames.length; l++) {
lbxTeacherName.addItem(lstTeacherNames[l],l);
}
var lblTeacherName = app.createLabel('Teacher Name:');
var txtTeacherName = app.createTextBox().setName('txtTeacherName').setId('txtTeacherName').setVisible(false);
var lblExt = app.createLabel('Ext:');
var txtExt = app.createTextBox().setName('txtExt').setId('txtExt');
//Set DateBox to Tomorrow's Date
var tomorrow =new Date(new Date(new Date().setHours(0,0,0,0)).setDate(new Date().getDate() + 1));// set hours, min, sec & milliSec to 0 and day=day+1
//Logger.log(tomorrow);
var lblDate = app.createLabel('Date of Test:');
var boxDate = app.createDateBox().setId('boxDate').setName('boxDate').setFormat(UiApp.DateTimeFormat.DATE_SHORT).setValue(tomorrow);
var lbxSubject = app.createListBox().setId('lbxSubject').setName('lbxSubject');
var lstSubjects = spSubjectList.getRange(1,1,spSubjectList.getLastRow(),1).getValues();
lstSubjects.sort();
for (var l = 0; l < lstSubjects.length; l++) {
lbxSubject.addItem(lstSubjects[l]);
}
var lbxPeriod = app.createListBox().setId('lbxPeriod').setName('lbxPeriod');
var lstPeriods = spPeriodList.getRange(1,1,spPeriodList.getLastRow(),1).getValues();
lstPeriods.sort();
for (var l = 0; l < lstPeriods.length; l++) {
lbxPeriod.addItem(lstPeriods[l]);
}
var lblStudentNum = app.createLabel('Number of Students:');
var lbxStudentNum = app.createListBox().setId('lbxStudentNum').setName('lbxStudentNum');
var lstStudentNums = spCountList.getRange(1,1,spCountList.getLastRow(),1).getValues();
lstStudentNums.sort();
for (var l = 0; l < lstStudentNums.length; l++) {
lbxStudentNum.addItem(lstStudentNums[l]);
}
var txtSourceGrp = app.createTextBox().setName('txtSourceGrp').setVisible(false);
var txtTypeGrp = app.createTextBox().setName('txtTypeGrp').setVisible(false);
var txtElementsID = app.createTextBox().setName('txtElementsID').setText('Elements Test ID').setVisible(false);
var txtQuiaLink = app.createTextBox().setName('txtQuiaLink').setText('Quia Test Link').setVisible(false);
var txtQuiaPass = app.createTextBox().setName('txtQuiaPass').setText('Quia Test Passphrase').setVisible(false);
//Create Source Radio Button Group
var radHCopy = app.createRadioButton('group1', 'Hard-Copy').setFormValue('Hard-Copy').addClickHandler(app.createClientHandler().forTargets(txtSourceGrp).setText('Hard-Copy'));
var radECopy = app.createRadioButton('group1', 'Electronic-Copy').setFormValue('Electronic-Copy').addClickHandler(app.createClientHandler().forTargets(txtSourceGrp).setText('Electronic-Copy'));
//Create Type Radio Button Group
var radTExam = app.createRadioButton('group2', 'Teacher-Made Exam').setFormValue('Teacher-Made Exam').addClickHandler(app.createClientHandler().forTargets(txtTypeGrp).setText('Teacher-Made Exam'));
var radEExam = app.createRadioButton('group2', 'Elements Exam').setFormValue('Elements Exam').addClickHandler(app.createClientHandler().forTargets(txtTypeGrp).setText('Elements Exam'));
var radQExam = app.createRadioButton('group2', 'Quia Exam').setFormValue('Quia Exam').addClickHandler(app.createClientHandler().forTargets(txtTypeGrp).setText('Quia Exam'));
var btnValidate = app.createButton('Create Event');
//Client Handlers for textBoxes
var showTxtElementHandler = app.createClientHandler().forTargets(txtElementsID).setVisible(true);
var hideTxtElementHandler = app.createClientHandler().forTargets(txtElementsID).setVisible(false);
radEExam.addClickHandler(showTxtElementHandler);
radTExam.addClickHandler(hideTxtElementHandler);
radQExam.addClickHandler(hideTxtElementHandler);
var showTxtQuiaLinkHandler = app.createClientHandler().forTargets(txtQuiaLink).setVisible(true);
var hideTxtQuiaLinkHandler = app.createClientHandler().forTargets(txtQuiaLink).setVisible(false);
radQExam.addClickHandler(showTxtQuiaLinkHandler);
radTExam.addClickHandler(hideTxtQuiaLinkHandler);
radEExam.addClickHandler(hideTxtQuiaLinkHandler);
var showTxtQuiaPassHandler = app.createClientHandler().forTargets(txtQuiaPass).setVisible(true);
var hideTxtQuiaPassHandler = app.createClientHandler().forTargets(txtQuiaPass).setVisible(false);
radQExam.addClickHandler(showTxtQuiaPassHandler);
radTExam.addClickHandler(hideTxtQuiaPassHandler);
radEExam.addClickHandler(hideTxtQuiaPassHandler);
//Create validation handler
var valSubmit = app.createServerClickHandler('valSubmit');
valSubmit.addCallbackElement(vrtMainPanel);
//Add this handler to the button
btnValidate.addClickHandler(valSubmit);
//Add all the elemnts to the panel
var formGrid = app.createGrid(12,3).setCellPadding(3);
vrtMainPanel.add(formGrid);
formGrid
.setWidget(0,0,lbxTeacherName)
.setWidget(0,1,txtExt)
.setWidget(0,2,txtTeacherName)
.setWidget(1,0,lbxPeriod)
.setWidget(1,1,lbxSubject)
.setWidget(2,0,lblDate)
.setWidget(2,1,boxDate)
.setWidget(3,0,lblStudentNum)
.setWidget(3,1,lbxStudentNum)
.setWidget(4,0,radHCopy)
.setWidget(4,1,radECopy)
.setWidget(5,0,radTExam)
.setWidget(6,0,radEExam)
.setWidget(6,1,txtElementsID)
.setWidget(7,0,radQExam)
.setWidget(7,1,txtQuiaLink)
.setWidget(8,1,txtQuiaPass)
.setWidget(9,0,txtSourceGrp)
.setWidget(9,1,txtTypeGrp)
.setWidget(10,0,btnValidate)
//Add this panel to the application
app.add(vrtMainPanel);
//Return the application
return app;
}
function valSubmit(e) {
var flag = 0;
var app = UiApp.getActiveApplication();
var Teacher = e.parameter.txtTeacherName;
var Ext = e.parameter.txtExt;
var Subject = e.parameter.lbxSubject;
var Period = e.parameter.lbxPeriod;
var Date = e.parameter.boxDate;
var StudentNum = e.parameter.lbxStudentNum;
var Source = e.parameter.txtSourceGrp;
var Type = e.parameter.txtTypeGrp;
var ElementsID = e.parameter.txtElementsID;
var QuiaLink = e.parameter.txtQuiaLink;
var QuiaPass = e.parameter.txtQuiaPass;
if (Teacher == '' || Teacher == '-- Select Teacher --') {
app.getElementById('vldTeacherName').setText('* Select Teacher').setStyleAttribute("color", "#F00").setVisible(true);
app.getElementById('lblNoSuccess').setStyleAttribute("color", "#F00").setVisible(true);
flag = 1;
}
if (Ext == '') {
app.getElementById('vldExt').setText('* Select Teacher Again').setStyleAttribute("color", "#F00").setVisible(true);
app.getElementById('lblNoSuccess').setStyleAttribute("color", "#F00").setVisible(true);
flag = 1;
}
if (Subject == '' || Subject == '-- Select Subject --') {
app.getElementById('vldSubject').setText('* Select Subject').setStyleAttribute("color", "#F00").setVisible(true);
app.getElementById('lblNoSuccess').setStyleAttribute("color", "#F00").setVisible(true);
flag = 1;
}
if (Period == '' || Period == '-- Select Period --') {
app.getElementById('vldPeriod').setText('* Select Period').setStyleAttribute("color", "#F00").setVisible(true);
app.getElementById('lblNoSuccess').setStyleAttribute("color", "#F00").setVisible(true);
flag = 1;
}
if (Date == '' || Date == Utilities.formatDate(Date, 'EST', 'yyyy-mm-dd')) {
app.getElementById('vldDate').setText('* Date must be entered as yyyy-mm-dd').setStyleAttribute("color", "#F00").setVisible(true);
app.getElementById('lblNoSuccess').setStyleAttribute("color", "#F00").setVisible(true);
flag = 1;
}
if (StudentNum == '' || StudentNum == '-- Select # --') {
app.getElementById('vldStudentNum').setText('* Select Student #').setStyleAttribute("color", "#F00").setVisible(true);
app.getElementById('lblNoSuccess').setStyleAttribute("color", "#F00").setVisible(true);
flag = 1;
}
if (Source == '' || Source == false) {
app.getElementById('vldSourceGrp').setText('* Select either Hard Copy or Electronic Copy').setStyleAttribute("color", "#F00").setVisible(true);
app.getElementById('lblNoSuccess').setStyleAttribute("color", "#F00").setVisible(true);
flag = 1;
}
if (Type == '' || Type == false) {
app.getElementById('vldTypeGrp').setText('* Select either Teacher-Made Exam, Elements Exam, or Quia Exam').setStyleAttribute("color", "#F00").setVisible(true);
app.getElementById('lblNoSuccess').setStyleAttribute("color", "#F00").setVisible(true);
flag = 1;
}
if (ElementsID == '' && Type == 'Elements Exam') {
app.getElementById('vldElementsID').setText('* Enter Elements ID').setStyleAttribute("color", "#F00").setVisible(true);
app.getElementById('lblNoSuccess').setStyleAttribute("color", "#F00").setVisible(true);
flag = 1;
}
if (QuiaLink == '' || QuiaPass == '' && Type == 'Quia Exam') {
app.getElementById('vldQuia').setText('* Enter Quia Link and/or Passphrase').setStyleAttribute("color", "#F00").setVisible(true);
app.getElementById('lblNoSuccess').setStyleAttribute("color", "#F00").setVisible(true);
flag = 1;
}
if (flag == 0) {
app.getElementById('lblSuccess').setStyleAttribute("color", "#F00").setVisible(true);
//Create handler which will execute 'createEvents(e)' on clicking the button
var evtHandler = app.createServerClickHandler('createEvents');
var vrtMainPanel = app.getElementById(vrtMainPanel);
evtHandler.addCallbackElement(vrtMainPanel);
}
}
function valHandler(e) {
var app = UiApp.createApplication().setTitle('DHS: Kurzweil Calendar');
//Create a panel which holds all the form elelemnts
var vrtMainPanel = app.createVerticalPanel().setId('vrtMainPanel');
var lblSuccess = app.createLabel('Check your information below, if everything looks correct you may confirm your event...').setName('lblSuccess').setId('lblSuccess').setVisible(false);
var lblNoSuccess = app.createLabel('There were issues with the creation of your event... click BACK, and make the following corrections:').setName('lblNoSuccess').setId('lblNoSuccess').setVisible(false);
var vldTeacherName = app.createLabel().setId('vldTeacherName').setVisible(false);
var vldExt = app.createLabel().setId('vldExt').setVisible(false);
var vldDate = app.createLabel().setId('vldDate').setVisible(false);
var vldSubject = app.createLabel().setId('vldSubject').setVisible(false);
var vldPeriod = app.createLabel().setId('vldPeriod').setVisible(false);
var vldStudentNum = app.createLabel().setId('vldStudentNum').setVisible(false);
var vldSourceGrp = app.createLabel().setId('vldSourceGrp').setVisible(false);
var vldTypeGrp = app.createLabel().setId('vldTypeGrp').setVisible(false);
var vldElementsID = app.createLabel().setId('vldElementsID').setVisible(false);
var vldQuia = app.createLabel().setId('vldQuia').setVisible(false);
var btnCreate = app.createButton('Corfirm Event');
//Add this handler to the button
var evtHandler = app.getElementById('evtHandler');
btnCreate.addClickHandler(evtHandler);
//Add all the elemnts to the panel
var formGrid = app.createGrid(13,3).setCellPadding(3);
vrtMainPanel.add(formGrid);
formGrid
.setWidget(0,0,lblSuccess)
.setWidget(1,0,lblNoSuccess)
.setWidget(2,0,vldTeacherName)
.setWidget(3,0,vldExt)
.setWidget(4,0,vldDate)
.setWidget(5,0,vldSubject)
.setWidget(6,0,vldPeriod)
.setWidget(7,0,vldStudentNum)
.setWidget(8,0,vldSourceGrp)
.setWidget(9,0,vldTypeGrp)
.setWidget(10,0,vldElementsID)
.setWidget(11,0,vldQuia)
.setWidget(12,0,btnCreate)
//Add this panel to the application
app.add(vrtMainPanel);
//Return the application
return app;
}
I've been spending a lot of time on form validation and I ended up with 2 possible solutions that work pretty well but since I can't decide which one is the best I use sometimes the first... and sometimes the second...
I'll show the idea of both solution, make your choice.
The 'logical' one : use client validation to enable the submit button and a few other client handler validations to show/hide warning labels near the fields that have to be filled. It works great but I must admit it can be tricky to write the script for it and needs quite a lot of code. (see examples in these post among others : Form validation on fields and FileUpload
Form validation using client handler : why does input sequence order change the result?
Use a server handler like you did in your code but replace the "createEvent" button with an intermediate button that instead of sending you directly to the event creation function calls a "fake" function that shows a summary of the requested data in a HTML widget with a nice looking presentation and another button that one use to confirm the event creation (and actually create the event) making a sort of 2 steps confirmation that is definitely user friendly. (and includes a way to go back one step to change/append the submitted data.
Both solution as I already said have pro and cons, the second one is just probably easier to write a script for it.
feel free to comment and/or ask for further details if the references I mentioned are not clear enough.
EDIT : here is an example of the 2cond approach and the spreadsheet with the included script (read only, make a copy to view/edit script and change the spreadsheet ID in the script if you want to run your own version))
The instructions are in french but it shouldn't be too hard to translate ... sorry about that :-) The SS has a marter sheet where you can define the question in the form and the script generates a custom form. There are tools to count responses, print log sheet per day and send confirmation emails.
Related
Google Sheet Apps Script Exceeding maximum time
I have a dynamic dropdown apps script running on only 1 cell and there are some other formulas running in my sheet. Until 2 days before i could run the script onEdit but i cant seem to do so now. When checked inside apps script execution page it shows "Exceeded maximum execution time". What can i do to resolve this? var mainWsName = "Print Sheet"; var mainDataName = "Orders"; var FirstLevelColumn = 1; var SecondLevelColumn = 2; var ThirdLevelColumn = 3; var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(mainWsName); var wsJO = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(mainDataName); var JO = wsJO.getRange(2,1,wsJO.getLastRow()-1,2).getValues(); function onEdit(e){ var activeCell = e.range; var val = activeCell.getValue(); var r = activeCell.getRow(); var c = activeCell.getColumn(); var wsName = activeCell.getSheet().getName(); if(wsName === mainWsName && c === FirstLevelColumn && r > 1){ applyFirstLevelValidation(val,r); }else if(wsName === mainWsName && c=== SecondLevelColumn && r > 1){ applysecondLevelValidation(val,r); } } //end onEdit function applyFirstLevelValidation(val,r){ if(val === ""){ ws.getRange(r,SecondLevelColumn).clearContent(); ws.getRange(r,SecondLevelColumn).clearDataValidations(); } else { ws.getRange(r,SecondLevelColumn).clearContent(); var filteredJO = JO.filter(function(o){return o[0] === val }); var listToApply = filteredJO.map(function(o){return o[1]}); var cell = ws.getRange(r,SecondLevelColumn); applyValidationToCell(listToApply,cell); } } function applyValidationToCell(list,cell){ var rule=SpreadsheetApp.newDataValidation().requireValueInList(list).setAllowInvalid(false).build(); cell.setDataValidation(rule); } Tried executing app script to get dynamic dropdown based on my selection.
The code you quote is suboptimal, but chances are that the bad performance you mention is caused by the spreadsheet rather than the script. To improve spreadsheet performance, see these optimization tips. You may also want to take a look at the dependentDropDownLists_ script.
Dependent Data Validation column script not rejecting input (Apps Script)
I made the following script to have a dependent dropdown data validation list for an entire column, however I can't seem to find a way to reject input if it's not valid, even with setAllowInvalid(), which I suspect is because I'm doing an offset. Any help would be greatly appreciated. var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); var data = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Cost Centers"); var ui = SpreadsheetApp.getUi(); var activeCell = ss.getActiveCell(); if(activeCell.getColumn() == 4 && activeCell.getRow() > 1) { if(activeCell.isBlank()){ activeCell.offset(0,1).clearContent().clearDataValidations(); } var departments = data.getRange(3,26,1,20).getValues(); var departmentIndex = departments[0].indexOf(activeCell.getValue()) + 26; if(departmentIndex != 0) { var validationRange = data.getRange(4,departmentIndex,60); var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).setAllowInvalid(true).build(); activeCell.offset(0,1).setDataValidation(validationRule); } } }
setAllowInvalid(false) setAllowInvalid(allowInvalidData) true if the rule should allow input that fails data validation; false if not.
Set the sourceRange of Data Validation to an array of values
I'm creating a social media outreach tracker. I want to create a drop-down list of the contact name. The problem is that I have two sources of names on two different sheets. I wrote a script that pulls the names from the two different sources and combines them to a single array. I was hoping to set the source range as that array. Here is my code: function setDataValid_(range, sourceRange) { var rule = SpreadsheetApp.newDataValidation() .requireValueInRange(sourceRange, true) .build(); range.setDataValidation(rule); } function onEdit() { var auditionsSheet = SpreadsheetApp.getActiveSpreadsheet(); var castingDirectorsTab = auditionsSheet.getSheetByName("Casting Directors"); var contactsTab = auditionsSheet.getSheetByName("Contacts"); var socialMediaOutreachTab = auditionsSheet.getSheetByName("Social Media Outreach"); var lastRowCD = castingDirectorsTab.getLastRow(); var lastRowContacts = contactsTab.getLastRow(); var activeCell = socialMediaOutreachTab.getActiveCell(); var activeColumn = activeCell.getColumn(); // get data var castingDirectorNameData = castingDirectorsTab.getRange(2, 1, lastRowCD, 1).getValues(); var contactNameData = contactsTab.getRange(2, 1, lastRowContacts, 1).getValues(); //get name data to a single arrays var castingDirectorName = []; castingDirectorNameData.forEach(function(yr) { castingDirectorName.push(yr[0]); }); var contactName = []; contactNameData.forEach(function(yr) { contactName.push(yr[0]); }); // get rid of the empty bits in the arrays for (var x = castingDirectorName.length-1; x > 0; x--) { if ( castingDirectorName[x][0] === undefined ) { castingDirectorName.splice( x, 1 ) } } for (var x = contactName.length-1; x > 0; x--) { if ( contactName[x][0] === undefined ) { contactName.splice( x, 1 ) } } //combine two data sources for data validation var combinedNames = []; combinedNames.push(castingDirectorName + contactName); Logger.log (combinedNames); Logger.log( typeof combinedNames); // data validation set up and build if (activeColumn == 1 && auditionsSheet.getName() == "Social Media Outreach") { var range = auditionsSheet.getRange(activeCell.getRow(), activeColumn +1); var sourceRange = combinedNames; setDataValid_(range, sourceRange) } } When I enter a date in Col A on Social Media Outreach, nothing happens in Col 2. I was using an existing working nested data validation script I have but the sourceRange pulls from a sheet based on the value in the active cell. Here is that code: function setDataValid_(range, sourceRange) { var rule = SpreadsheetApp.newDataValidation() .requireValueInRange(sourceRange, true) .build(); range.setDataValidation(rule); } function onEdit() { var aSheet = SpreadsheetApp.getActiveSheet(); var aCell = aSheet.getActiveCell(); var aColumn = aCell.getColumn(); // data validation for Auditions Tab Projet Type to Project Details if (aColumn == 9 && aSheet.getName() == 'Auditions') { var range = aSheet.getRange(aCell.getRow(), aColumn + 1); var sourceRange = SpreadsheetApp.getActiveSpreadsheet().getRangeByName('RefTables!' + aCell.getValue()) setDataValid_(range, sourceRange) } } For this script when I select from the data validation drop-down, a new data validation comes up in the next col with the appropriate secondary data validation. So the question is, can the source range be set to an array or do I need to put the names back into my sheet to reference a la the second script. I've looked through the documentation and searched and can't find an answer. I'm relatively new to GAS and am not sure of all the inner workings of the data validation builder.
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!
Updating Panel with new values in GAS UI
I have a huge spreadsheet matrix, from which I create a long list of check boxes. The users then select different abilities, press search. The code the cross-checks with the database spreadsheet, returning names of the persons who has those abilities. I need to update the "rightPanel" with the results of my search. But i simple can't figure out how to - if at all posible - update a panel in my UI.. var dataSSkey = 'sheetID'; //datasheet ID var dataSheet = SpreadsheetApp.openById(dataSSkey).getSheetByName('Ansatte'); var groupsArray = [[],[],[],[]]; var lastRow = dataSheet.getLastRow(); var lastColumn = dataSheet.getLastColumn(); var dataArray = dataSheet.getRange(1,1,lastRow,lastColumn).getValues(); var numberGroups var app = UiApp.createApplication().setTitle('Find Consultant'); var panel = app.createVerticalPanel(); var leftPanel = app.createVerticalPanel().setWidth(450); var rightPanel = app.createVerticalPanel().setWidth(450); var grid = app.createGrid(1, 2).setId('myGrid') var outputArray = []; //to store output from search var positiveList = [[],[]]; //array to store name and folder-ID of consultants matching var numberPositive = 0; //number of consultants matching function doGet() { buildGroupsArray() addCheckBoxesToUI() var scrollPanel = app.createScrollPanel().setHeight(460); //Search button var searchButton = app.createButton('Search'); var clickHandler = app.createServerClickHandler("respondToSearch"); searchButton.addClickHandler(clickHandler); clickHandler.addCallbackElement(panel); var spacerImage = app.createImage("http://www.bi..ge.jpg").setHeight(3); scrollPanel.add(panel); rightPanel.add(app.createLabel('resultat her')); leftPanel.add(scrollPanel); leftPanel.add(spacerImage); leftPanel.add(searchButton); grid.setWidget(0, 0, leftPanel) grid.setWidget(0, 1, rightPanel); app.add(grid); return app; } function respondToSearch(e){ var numberLogged = 0; //define firstEmpty var firstEmpty = "A"+lastRow; if(lastRow !== 1){ firstEmpty = "A"+(lastRow+1); }; //find selected competencies --> store in array + count competencies for(i = 1; i <= lastRow; i++){ if (e.parameter["Checkbox"+i] == "true") { var value = e.parameter["CheckboxValue"+i]; outputArray[numberLogged] = value; numberLogged++; } } for(i = 2; i <= lastColumn; i++){ var numberCorrect = 0; //Run through rows according to content of output from selection for(j in outputArray){ //Check if consultant own selected competency if(dataArray[outputArray[j]][i] == "x"){ numberCorrect++; //if consultant owns selected competency then count } } //if consultant owns all competencies, then add name and folder-id to array if(numberCorrect == numberLogged){ positiveList[0][numberPositive] = dataArray[1][i]; //Add consultant name positiveList[1][numberPositive] = dataArray[2][i]; //Add consultant-folder ID numberPositive++ //count the number of consultants that own all competencies } } for(j in positiveList[0]){ var name = positiveList[0][j]; var id = positiveList[1][j]; Logger.log(name); Logger.log(id) var anchor = app.createAnchor(name,'https://ww......folderviewid='+id); rightPanel.add(anchor) } return app; }
I don't really understand the problem you have... In your handler function you only have to use app=UiApp.getActiveApplication() and from there populate the panel exactly the same way you did it in the doGet() function, ending with a return app; that will actually update the current Ui. There are dozens of examples all around... did I misunderstand something in your question ? Edit : following your comment. I suppose you defined your variables outside of the doGet function hoping they will become global and so available to all the functions in your script but this is not going to work. Global variables in Google Apps script can't be updated by functions. I would strongly recommend that you create app and panels in the doGet function and give them an ID so that you can get them back and update their values (or content) from the handler functions. Here is a re-written version of your code (didn't test) : (some parts are not reproduced (see //...) var dataSSkey = 'sheetID'; //datasheet ID var dataSheet = SpreadsheetApp.openById(dataSSkey).getSheetByName('Ansatte'); var groupsArray = [[],[],[],[]]; var lastRow = dataSheet.getLastRow(); var lastColumn = dataSheet.getLastColumn(); var dataArray = dataSheet.getRange(1,1,lastRow,lastColumn).getValues(); var numberGroups var outputArray = []; //to store output from search var positiveList = [[],[]]; //array to store name and folder-ID of consultants matching var numberPositive = 0; //number of consultants matching function doGet() { var app = UiApp.createApplication().setTitle('Find Consultant'); var panel = app.createVerticalPanel(); var leftPanel = app.createVerticalPanel().setWidth(450).setId('leftPanel'); var rightPanel = app.createVerticalPanel().setWidth(450).setId('rightPanel');; var grid = app.createGrid(1, 2).setId('myGrid') buildGroupsArray(app); // in this function get app as parameter or use UiApp.getActiveApplication(); addCheckBoxesToUI(app);// in this function get app as parameter or use UiApp.getActiveApplication(); var scrollPanel = app.createScrollPanel().setHeight(460); //... //... return app; } function respondToSearch(e){ //... //... var app = UiApp.getActiveApplication(); var rightPanel = app.getElementById('rightPanel'); for(j in positiveList[0]){ var name = positiveList[0][j]; var id = positiveList[1][j]; Logger.log(name); Logger.log(id) var anchor = app.createAnchor(name,'https://ww......folderviewid='+id); rightPanel.add(anchor) } return app; }