Google AppScript - Update google Form using appscript - google-apps-script

I have the following scenario
I currently update my form using appscript which is working fine however I have this problem , my form has question to select a country (from drop down list of countries ) and each option has each section mapped , (say if I select country as Netherlands whilst filling the form , it will take me to next section to select the town in Netherlands in the specified section ), so what happens now is whenever there is new country added in the sheet its updated in the form via below script and it works fine but it resets the section map that is set for each country , so we have to redo the section based answer again ! wanted to understand is there any way that to avoid resetting the section based options thats set.
Code
var ssID = "sheet ID"; //Global Variable sheet ID
// This is start of function1 to update form Monthly
function formUpdateCC() {
// call your form and connect to the drop-down item
var form = FormApp.openById("form ID");
var country = form.getItemById("ItemID").asListItem();
// identify the sheet where the data resides needed to populate the drop-down - Countrylist
var countrysheet = SpreadsheetApp.openById(ssID).getSheetByName("Country");
// grab the values in the first column of the country tab in sheet - use 2 to skip header row
var countrylist = countrysheet.getRange(2, 1, countrysheet.getMaxRows() - 1).getValues();
var data = [];
// convert the array ignoring empty cells
for (var i = 0; i < countrylist.length; i++)
if (countrylist[i][0] != "")
data[i] = countrylist[i][0];
country.setChoiceValues(data);
}

You can use setChoices with createChoice(value, navigationItem) instead of setChoiceValues to add navigation to choices. Create a new column (in this example, it's column B) with the section ID for the section you'd like to navigate for that country. Then use the code below to update the form.
var form = FormApp.openById("Form Id");
var country = form.getItemById("List Id").asListItem();
// identify the sheet where the data resides needed to populate the drop-down - Countrylist
var countrysheet = SpreadsheetApp.openById(ssID).getSheetByName("Country");
// create a new column next to the country name for its target pagebreak ID from the form
// grab the values in the first & second columns of the country tab in sheet - use 2 to skip header row
var countrylist = countrysheet.getRange(2, 1, countrysheet.getMaxRows() - 1).getValues();
var targetlist = countrysheet.getRange(2, 2, countrysheet.getMaxRows() - 1).getValues();
var data = [];
// convert the array ignoring empty cells
var s = 0;
for (var i = 0; i < countrylist.length; i++)
if (countrylist[i][0] != "") {
// use createChoice(value, navigationItem) to add the section navigation
data[s] = country.createChoice(countrylist[i][0], form.getItemById(targetlist[i][0]).asPageBreakItem());
s++;
}
country.setChoices(data);

Related

Is there a way to copy data from a three column list into a different sheet based on the values in one of the columns?

I have am creating budget spreadsheet that has a summary of the amounts remaining in each category in the first tab
screenshot of the budget tab
I would like to make a macro that takes all those values and copies them into a different tab for tracking purposes. The new tab has the date, paycheck amount and each category in the first row, and the values should be copied in the rows following. If someone changes the order of the categories, I would like the macro to still find the correct column and paste it there. Likewise, if someone were to add a new category, I would like the macro to add that category to the first blank column.
Here is what the tracking sheet looks like
screenshot of the budget tracking sheet
So far I have written this code and have noted where it stops working.
function rollover1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cb = ss.getSheetByName('Current Budget');
var bt = ss.getSheetByName('Budget Tracking');
var btlr = bt.getLastRow()+1;
//copy over date and paycheck value
bt.getRange(btlr,1).setValue(cb.getRange('C3').getValue());
bt.getRange(btlr,2).setValue(cb.getRange('C4').getValue());
//get number of areas
var numareas = (ss.getRange('B6').getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()-6);
//search each budget area and paste value for period, this is where it stops working
var id, blank, amt;
var areas = cb.getRange(6,1,numareas,3).getValues();
[id] = areas[0];
[blank] = areas[1];
[amt] = areas[2];
blank = Number(blank.split(" ")[1]);
var ids = bt.getRange("A1:AEP1").getValues();
for (var i=0; i<ids[0].length; i++) {
if (ids[0][i] == id) {
bt.getRange(bt.getLastRow() + 1, i + 1, 1, 2).setValues([[id,amt]]);
}
}

Google Sheets Script: Use data to make a new tab and export matching information to the new tab

I'm working on a script that will take a manufacturer's name from a column in one tab, use that name to create a new tab, and export data on all products in the list made by that manufacturer to the newly created tab. The main tab from which the manufacturer names would be pulled, called Pricebook, has around 10,000 lines, with columns like Manufacturer, UPC, and Price. There is another tab called MFG which allows me to choose which manufacturers I'd like to run a report on. I have been able to use the script to create new tabs, but I can't figure out how to get the data from "Pricebook" to transfer over into the newly created tabs. Below is part of my script. The top function creates the new tabs, and the bottom function exports the information to the new tab.
function newTabsAndData() { //create tabs based on selected mfgs, move relevant data to each tab
var ss = SpreadsheetApp.getActiveSpreadsheet();
var main = ss.getSheetByName('PRICEBOOK'); //all pricing data
var mfgs = ss.getSheetByName('MFGs'); //Manufacutrer's names
mfgs.getRange(2,2,mfgs.getLastRow(),2).copyTo(mfgs.getRange(2,2,mfgs.getLastRow(),2),{contentsOnly:true}); //columns b and c removes formula and pastes only value to same column
mfgs.getRange(2,1,mfgs.getLastRow(),3).sort([{column:1, ascending:false}, {column:3, ascending:true}]); //sort by True(1) then mfg name(3).
var mfgscvals = mfgs.getRange("C2:C").getValues().filter(String).length; //finds values and last row in MFGs column C to name tabs
var dataMain = main.getRange(2,1,main.getLastRow(),main.getLastColumn()).getValues(); //range of data from PRICEBOOK to move to new tabs
var outData = []
for(var i = 1; i < mfgscvals+1; i++){ //look at C on MFGs and collect name one at a time. for = loop the following. java starts at 0, so i = 1 starts on row 2
var tabName = mfgs.getRange(i+1,3).getValue(); //get name from column 3 of MFGs and create new tab(insert sheet) with that name
ss.insertSheet(tabName);
}
};
function moveData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var main = ss.getSheetByName('PRICEBOOK'); //all pricing data
var mfgs = ss.getSheetByName('MFGs'); //Manufacutrer's names
mfgs.getRange(2,2,mfgs.getLastRow(),2).copyTo(mfgs.getRange(2,2,mfgs.getLastRow(),2),{contentsOnly:true}); //columns b and c removes formula and pastes only value to same column
mfgs.getRange(2,1,mfgs.getLastRow(),3).sort([{column:1, ascending:false}, {column:3, ascending:true}]); //sort by True(1) then mfg name(3).
var mfgscvals = mfgs.getRange("C2:C").getValues().filter(String).length; //finds values and last row in MFGs column C to name tabs
var dataMain = main.getRange(2,1,main.getLastRow(),main.getLastColumn()).getValues(); //range of data from PRICEBOOK to move to new tabs
var outData = []
var shts = ss.getSheets();
for (j = 3; j < shts.length; j++){
shts[j].getSheetName()
if (shts[j] == dataMain[2]){
outData.push(dataMain[0])
//for (var j in dataMain){
//if (dataMain[j][2] == tabName){ //loop col 3 of PRICEBOOK, if tabName(mfg name) = dataMain C, then move data to tab with mfg name
//outData.push(dataMain[j])
}
var mfgName = ss.getSheetByName(shts[j]); //moves correct data to first tab, moves data from first tab and second to second tab, 1,2,& 3 to third etc
mfgName.getRange(mfgName.getLastRow()+1,1,outData.length,outData[0].length).setValues(outData);
}
}
Any help is greatly appreciated.

Update multiple rows of data in google sheet into multiple sections of google form

Currently using the below app script function to update one column of data into one section of my google form. However, I want to write a code where I can update multiple rows of data into multiple sections of the google form.
Example: Column 1 update to Section 1, Column 2 update to Section 2 and etc..
Google Sheet - Employee Names
function updateForm(){
// call your form and connect to the drop-down item
var form = FormApp.openById("Form Id");
var namesList = form.getItemById("Dropdown List ID").asListItem();
// identify the sheet where the data resides needed to populate the drop-down
var ss = SpreadsheetApp.getActive();
var names = ss.getSheetByName("Sheet Name");
// grab the values in the first column of the sheet - use 2 to skip header row
var namesValues = names.getRange(2, 10, names.getMaxRows() - 1).getValues();
var shopperNames = [];
// convert the array ignoring empty cells
for(var i = 0; i < namesValues.length; i++)
if(namesValues[i][0] != "")
shopperNames[i] = namesValues[i][0];
// populate the drop-down with the array data
namesList.setChoiceValues(shopperNames);
}
For better organisation, please arrange the data as below
Name - Address
This way you can add new persons easily and change the address easily.
After that, it becomes easy to filter the range by column B and you can easily get the list of persons in the street.
ArrayFormula makes it very easy to do this
https://sites.google.com/site/scriptsexamples/custom-methods/2d-arrays-library

Populating a Google From DropDown with Values from a Google Sheet

I looked through all of the questions, and I can't quite figure out what I am doing wrong. Here is the background:
I created a spreadsheet that has multiple tabs. Each tab corresponds to types of events (e.g parades, festivals, sports). Each of these tabs is used to assign specific job numbers to a specific event. Parade job numbers are in the 2000 range, festivals 3000 range, sports 4000 range.
I then have a different tab which defines an array that collects all of the job numbers and events, and sorts them alphabetically. This tab is called "Active_Job_Numbers".
My goal is to create several forms that call to this spreadsheet for the values on the "Active_Job_Numbers" tab. I sort of have this working, but not completely. Each form has a purpose such as submitting a request to accounting to process a credit card transaction; another form to submit a request to cut a check.
All of these requests have to be tied to an ever changing list of job numbers. When I update the spreadsheet, the dropdown in the spreadsheet will populate based on the "Active_Job_Numbers" data.
The code that I am using does work, BUT if I update a job number or event name on the spreadsheet, the form still sees the old value. I have triggers set up for onSubmit and onOpen and still, the only way I can get the dropdown in the form to update is if I change one of the "var" labels. Then save it. Then reopen the form. This is a showstopper.
Here is the code I am using:
function updateForm(){
// call your form and connect to the drop-down item
var creditCardRequestGoogleForm = FormApp.openById("1LqtPLGEhocGdkg75mkdldfplxSxWJmYZCp3u1bMwVQQ");
var jobNumberDropDown = creditCardRequestGoogleForm.getItemById("1632374512").asListItem();
// identify the sheet where the data resides needed to populate the drop-down
var ss = SpreadsheetApp.openById("17fgel9Jfl4Aske85mfkwsphBQpZgtGhR8Q");
SpreadsheetApp.setActiveSpreadsheet(ss);
var activeJobNumbers = ss.getSheetByName('Active_Job_Numbers');
// grab the values in the first column of the sheet - use 2 to skip header row
var jobNumValues = activeJobNumbers.getRange(2, 1, activeJobNumbers.getMaxRows() - 1).getValues();
var jobNums = [];
// convert the array ignoring empty cells
for(var i = 0; i < jobNumValues.length; i++)
if(jobNumValues[i][0] != "")
jobNums[i] = jobNumValues[i][0];
// populate the drop-down with the array data
jobNumberDropDown.setChoiceValues(jobNums);
}
A separate but related problem...there are some forms I have that have two different drop-down elements that call to the same spreadsheet but to different tabs. I am not sure how to group this script so I have to separated out like so:
function updateForm(){
// call your form and connect to the drop-down item
var ccrForm = FormApp.openById("1r5n6Sr7fhtGCqht_QHy9qWR1v2ESabxdE-bMxjR-M");
var jobNumberDropDown = ccrForm.getItemById("1678955392").asListItem();
// identify the sheet where the data resides needed to populate the drop-down
var ss = SpreadsheetApp.openById("17eGAlcnBB7ejdfqp3HBQBK9wJAKWYhBQpZgtGhR8Q");
SpreadsheetApp.setActiveSpreadsheet(ss);
var currentJobNumbers = ss.getSheetByName('Active Job Numbers');
// grab the values in the first column of the sheet - use 2 to skip header row
var jobNumValues = currentJobNumbers.getRange(2, 1, currentJobNumbers.getMaxRows() - 1).getValues();
var jobNums = [];
// convert the array ignoring empty cells
for(var i = 0; i < jobNumValues.length; i++)
if(jobNumValues[i][0] != "")
jobNums[i] = jobNumValues[i][0];
// populate the drop-down with the array data
jobNumberDropDown.setChoiceValues(jobNums);
}
function updateForm(){
// This call your form and connect to the drop-down item
var form = FormApp.openById("1r5n6Sr7fhtGCqht_QHy9qWR1v2ESabxdE-bMxjR-M");
var poNumberDropDown = form.getItemById("57865789991").asListItem();
// This is the second dropdown which calls the same spreadsheet but different tab NEED HELP COMBINING THESE TWO MORE ELEGANTLY
var ss = SpreadsheetApp.openById("17eGAlcnBB7ejdfqp3HBQBK9wJAKWYhBQpZgtGhR8Q");
SpreadsheetApp.setActiveSpreadsheet(ss);
var currentPONumbers = ss.getSheetByName('PO_Number');
// grab the values in the first column of the sheet - use 2 to skip header row
var poNumValues = currentPONumbers.getRange(2, 1, currentPONumbers.getMaxRows() - 1).getValues();
var poNums = [];
// convert the array ignoring empty cells
for(var i = 0; i < poNumValues.length; i++)
if(poNumValues[i][0] != "")
poNums[i] = poNumValues[i][0];
// populate the drop-down with the array data
poNumberDropDown.setChoiceValues(poNums);
}
Any insight would be much appreciated.
onOpen trigger for a form, as mentioned in documentation:
This event does not occur when a user opens a form to respond, but
rather when an editor opens the form to modify it
Instead, you can use an installable trigger to activate your code when the sheet is edited.
Furthermore, instead of modifying all form each time an edit is made on the spreadsheet. You can check for which sheet is modified in the spreadsheet to modify the corresponding form. To determine the which sheet is modified you can use event objects.
Here is example code, you can modify this for your use.
function installedEdit(evtObj){
Logger.log("Edit running")
var sheetName = evtObj.range.getSheet().getSheetName()
Logger.log(sheetName)
var itemId="None"
switch (sheetName){
case "Active Job Numbers":
itemId = "1678955392"
updateForm(sheetName,itemId)
break;
case "PO_Number":
itemId = "57865789991"
updateForm(sheetName,itemId)
break;
}
}
function updateForm(sheetName,itemId){
// call your form and connect to the drop-down item
var form = FormApp.openById("1r5n6Sr7fhtGCqht_QHy9qWR1v2ESabxdE-bMxjR-M");
var dropDown = form.getItemById(itemId).asListItem();
// identify the sheet where the data resides needed to populate the drop-down
var ss = SpreadsheetApp.openById("17eGAlcnBB7ejdfqp3HBQBK9wJAKWYhBQpZgtGhR8Q");
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = ss.getSheetByName(sheetName);
// grab the values in the first column of the sheet - use 2 to skip header row
var choiceValues = sheet.getRange(2, 1, sheet.getLastRow() - 2).getValues();
var choices = [];
// convert the array ignoring empty cells
for(var i = 0; i < choiceValues.length; i++)
if(choiceValues[i][0] != "")
choices[i] = choiceValues[i][0];
// populate the drop-down with the array data
dropDown.setChoiceValues(choices);
}
Note: Make sure installedEdit() is set up to run when the spreadsheet is edited and is bound to the spreadsheet.

Google App Scripts(spreadsheet) - consolidate data into one sheet

Here is the set up
We have a contest with all employees based on project scores. Each project has two categories of employees(4 employees per category) and two scores(one for each category of employee).
I need to grab all the scores for the employees and output it into a spreadsheet. The following spreadsheet has misc. columns removed
Sheet Explanation
The sheet labeled "Example data" is the source we will be pulling data from
We need to match Editor and Editor Score
We need to match Webmaster and webmaster score
The sheet labeled "Example output" is what I want to be generated in another spreadsheet named "Contest Result" with the sheet name from the source sheet(They are named by date ranges).
We need to compile each employee by the categories
We need to compile all scores to the row for a singular employee
I had found this Removing Duplicates Article that seemed to at least process the information and compare it in a manner that I think this can be done, but am failing to make it work due to being inexperienced.
Did not know what Transpose was till someone commented :)
Here is the solution in another article for how to pull it off with Google Apps Script and with using the spreadsheet option.
How to split and transpose results over 2 columns
Here is the actual code I used to make it work(it is a little horrible but I tried) suggestions on how to improve this?:
function createScoreSheet() {
// Get Source spreadsheet
var source = SpreadsheetApp.getActive();
var sourceSheet = source.getActiveSheet();
var SourceActivate = sourceSheet.activate();
// Set Sheet Name
var sheetName = sourceSheet.getSheetName();
// Set Values to transpose and combine
var sourceEditor = sourceSheet.getRange("C1:C51");
var sourceWeb = sourceSheet.getRange("D1:D51");
var editorScores = sourceSheet.getRange("L1:L51");
var webScores = sourceSheet.getRange("K1:K51");
// Used to create a new spreadsheet
var sheetNameNew = sheetName + " Scores";
var createSheet = SpreadsheetApp.getActive().insertSheet(sheetNameNew,0);
var targetSheet = source.getSheetByName(sheetNameNew);
var totalScore = 1;
// s is the the counter we use to stick values into the rows
var s = 3;
// n is the the counter we use to stick values into the columns
var n = 1;
// loops through twice, once for the editor values, once for the webmaster
for (var j = 1; j<3; j++) {
if (j == 1) {
// grab values for the editors and copy to new sheet
sourceEditor.copyTo(targetSheet.getRange("A1"));
editorScores.copyTo(targetSheet.getRange("B1"));
// delete the header row then sort the column ASC by default
targetSheet.deleteRow(n);
targetSheet.sort(1);
// Find the last value to see how many scores we have
var lastRow = targetSheet.getLastRow();
}
if (j == 2) {
// grab values for the webmasters and copy to new sheet
sourceWeb.copyTo(targetSheet.getRange(n,1));
webScores.copyTo(targetSheet.getRange(n,2));
// delete the header row then sort the column ASC by default
targetSheet.deleteRow(n);
lastRow = targetSheet.getLastRow();
targetSheet.getRange(n,1,lastRow,2).sort(1);
lastRow = targetSheet.getLastRow();
}
// this loop will check to see if the value of the cell is equal to the next on the list and move the score
for (var i = 1; i<lastRow+1; i++) {
// Grab the name of the current row and the next
var firstName = targetSheet.getRange(n,1).getValue();
var nextName = targetSheet.getRange(n+1,1).getValue();
// Grab the scores
var oldScore = targetSheet.getRange(n+1,2);
var newScore = targetSheet.getRange(n,s);
// Loop to check to see if the firstname is blank and break to find the next value
if (firstName === "") {
break;
}
// checks to see if name is equal to the next then shifts then copies the score and adjust the horizontal position
if (firstName == nextName) {
totalScore = oldScore + newScore;
oldScore.copyTo(newScore);
s = s+1;
targetSheet.deleteRow(n+1);
}
// resets horizontal position for the score and increases the row
else {
s=3;
n=n+1;
}
}
// kills remaining rows
targetSheet.deleteRows(n,37);
}
}
I would do it like this:
If you want to generate the names automatically as well, then write this to the output sheet A1:
=unique('Example Data'!B2:B) - This function simply generate the editor names to the A2-A5 cells.
Now write this to the B2 cell:
=transpose(filter('Example Data'!E:E,'Example Data'!B:B=A2)) - This function filters the editor points according to the given name in the beginning of the row (in this case its A2). Then transposes the result in a horizontal form. To get the result for the other rows, simply populate this formula down.
I think you can find out the rest. :)
Hope it helps.