Google Form Drop Down and Sections with Loop - javascript

So I have this project I am working on where I need to create a Google Form based on names in a Google Sheet. The way it basically needs to flow is for every name in the sheet should be an option as a drop down in section one and then have a section created for each name. When the person selects their name in the first section they should then be sent to the section titled their name. For example, Name 1 should go to the section titled Name 1, Name 2 to Name 2, etc. The code below will create a Google Form and create sections with the names. The issue that arouses is it will not add the names to a drop down list (it will create a drop down list with no options) and will also not set a destination based on the answers. Any thoughts?
function RecommendationForm(){
var form = FormApp.create('FANS Recommendation Form');
form.setTitle('FANS Recommendation Form')
.setConfirmationMessage('Thanks for responding!')//SET CONFIRMATION MESSAGE LATER
.setAllowResponseEdits(false)
.setAcceptingResponses(true);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Teacher and Email List');
var startRow = 2;
var numRows = 200;
var dataRange = sheet.getRange(startRow, 1, numRows, 4)
var data = dataRange.getValues();
var whoAreYou = form.addListItem();
whoAreYou.setTitle('Who are you?')
var nameBreak = []
var nameChoice = []
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var name = row[0];
var recNumber = row[2]
if (name != ""){
if (recNumber != 0){
nameBreak[i] = form.addPageBreakItem().setTitle(name);
nameChoice[i] = name
}}};
whoAreYou.setChoices([
whoAreYou.createChoice(nameChoice,nameBreak)
])
}

You got the syntax of the setChoices function wrong. You need to create an array of choices like so:
var choices = []
choices[i] = whoAreYou.createChoice(name,form.addPageBreakItem().setTitle(name))
Then you can use this array in setChoices method to set all your choices.
whoAreYou.setChoices(choices)
for more details have a look here
Below is the modified code that incorporates these changes,
function RecommendationForm(){
var form = FormApp.create('FANS Recommendation Form');
//var form = FormApp.openByUrl("https://docs.google.com/forms/d/11oaebH_BeFLAkpGjqs5EykqtNxXXaabuVCTk3uuc12s/edit")
form.setTitle('FANS Recommendation Form')
.setConfirmationMessage('Thanks for responding!')//SET CONFIRMATION MESSAGE LATER
.setAllowResponseEdits(false)
.setAcceptingResponses(true);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet9');
var startRow = 2;
var numRows = 10;
var dataRange = sheet.getRange(startRow, 1, numRows, 4)
var data = dataRange.getValues();
var whoAreYou = form.addListItem();
whoAreYou.setTitle('Who are you?')
var nameBreak
var nameChoice
var choices = []
var choiceCounter = 0
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var name = row[0];
var recNumber = row[2]
if (name != ""){
if (recNumber != 0){
nameBreak = form.addPageBreakItem().setTitle(name);
nameChoice = name
choices[choiceCounter] = whoAreYou.createChoice(nameChoice,nameBreak) // Create a array of choices with the navigation item
choiceCounter++; // This counter will be independent of i counter and will be have no breaks.
}}
};
whoAreYou.setChoices(choices) //Set Choices with the choice array.
Logger.log(form.getEditUrl())
Logger.log(form.getPublishedUrl())
}
Hope this helps!

Related

Get created and modified date after editing response from google forms

function assignEditUrls() {
var form = FormApp.openById('Your form key goes here');
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Your responses Google Sheet name goes here - The tab name, not the file name');
var data = sheet.getDataRange().getValues();
var urlCol = Column number where URLs get entered goes here;
var responses = form.getResponses();
var timestamps = [],
urls = [],
resultUrls = [];
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0] ? urls[timestamps.indexOf(data[j][0].setMilliseconds(0))] : '']);
}
sheet.getRange(2, urlCol, resultUrls.length).setValues(resultUrls);
}
I am currently using this code which allows me to update the record which is generating a edit link to edit that respective record. But the challenge is that it also changes the timestamp.
Question is
How can we amend this code so i can get created and last modified date and time for the particular record in the google sheet?
Any help much appreciated. Many thanks.
You can create an onFormSubmit Trigger to save the created date of your rows whenever a new record is added. By using this method, we can easily store the Created Date and the Modified Date (Timestamp) which you can use for other operations.
Example:
Here I updated the email of Test Data 1:
Before:
After:
Code:
function assignEditUrls() {
var form = FormApp.openById('Enter form id here');
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses 1');
var data = sheet.getDataRange().getValues();
var urlCol = 9;
var responses = form.getResponses();
var urls = [];
for (var i = 0; i < responses.length; i++) {
urls.push([responses[i].getEditResponseUrl()]);
}
sheet.getRange(2, urlCol, urls.length).setValues(urls);
}
function triggerTest(e){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses 1');
var createdDateCol = 8;
var row = e.range.getRow();
sheet.getRange(1, createdDateCol, 1, 1).setValue("Created Date"); // Add created date header
var cdRange = sheet.getRange(row, createdDateCol, 1, 1);
if(cdRange.getValue() == ''){ // this indicates that the record is new
cdRange.setValue(e.namedValues['Timestamp'])
}
}
Reference:
Installable Triggers

Copy Selected Columns in One Sheet and Add Them To Selected Columns in Another Sheet

I would like to create a simple google apps script to copy specific column into another sheets.
Previously I tried using getLastRow but I get stuck to modify it.
var destinationSheetLastRow = destinationSheet.getDataRange().getLastRow();
Here is my spreadsheet: https://docs.google.com/spreadsheets/d/1rGvmlKCmbjDSCLCC2Kujft5e4ngbSLzJd2NYu0sxISs/edit?usp=sharing
And here is the modified script so far:
function pasteMultiCol(sourceSheet, destinationSheet,sourceColumns,destinationColumns, doneColumn){
var sourceDataRange = sourceSheet.getDataRange();
var sourceDataValues = sourceDataRange.getValues();
var sourcesheetFirstRow = 0;
var sourceSheetLastRow = sourceDataRange.getLastRow();
var destinationSheetLastRow = destinationSheet.getDataRange().getLastRow();
var pendingCount = 0;
//Find the row start for copying
for(i = 0; i < sourceDataValues.length; i++){
if(sourceDataValues[i][doneColumn-1] === "Copied"){
sourcesheetFirstRow++;
};
if(sourceDataValues[i][doneColumn-1] === ""){
pendingCount++;
};
};
//Update Source sheet first row to take into account the header
var header = sourceSheetLastRow-(sourcesheetFirstRow + pendingCount);
sourcesheetFirstRow = sourcesheetFirstRow+header;
// if the first row equals the last row then there is no data to paste.
if(sourcesheetFirstRow === sourceSheetLastRow){return};
var sourceSheetRowLength = sourceSheetLastRow - sourcesheetFirstRow;
//Iterate through each column
for(i = 0; i < destinationColumns.length; i++){
var destinationRange = destinationSheet.getRange(destinationSheetLastRow+1,
destinationColumns[i],
sourceSheetRowLength,
1);
var sourceValues = sourceDataValues.slice(sourcesheetFirstRow-1,sourceSheetLastRow);
var columnValues =[]
for(j = header; j < sourceValues.length; j++){
columnValues.push([sourceValues[j][sourceColumns[i]-1]]);
};
destinationRange.setValues(columnValues);
};
//Change Source Sheet to Copied.
var copiedArray =[];
for(i=0; i<sourceSheetRowLength; i++){copiedArray.push(["Copied"])};
var copiedRange = sourceSheet.getRange(sourcesheetFirstRow+1,doneColumn,sourceSheetRowLength,1)
copiedRange.setValues(copiedArray);
};
function runsies(){
var ss = SpreadsheetApp.openById("1snMyf8YZZ0cGlbMIvZY-fAXrI_dJpPbl7rKcYCkPDpk");
var source = ss.getSheetByName("Source");
var destination = ss.getSheetByName("Destination");
var sourceCols = [4,5,6,7,8,9,10];
var destinationCols = [7,8,9,10,11,12,13];
var doneCol = 12
//Run our copy and append function
pasteMultiCol(source,destination, sourceCols, destinationCols, doneCol);
};
Your code is taken from my tutorial in my blog article Copy Selected Columns in One Sheet and Add Them To The Bottom of Different Selected Columns in Another Sheet and it just needs a tweak.
I think the issue might be that you have a bunch of formulas in other columns in your "Destination" Sheet tab. So getting the last row of the sheet will result in getting the last row considering all the data including your other formulas.
You might find this explanation in a follow up blog article I wrote helpful: Google Apps Script: Get the last row of a data range when other columns have content like hidden formulas and check boxes
In short, you can change the destinationSheetLastRow variable to something simple like this.
var destinationSheetLastRow = (()=>{
let destinationSheetFirstRow = 7; // The first row of data after your header.
//Get a sample range to find the last value in the paste columns.
let sampleRange = destinationSheet.getRange(destinationSheetFirstRow,
destinationColumns[0],
destinationSheet.getLastRow())
.getValues();
let sampleLastRow = 0;
while(sampleLastRow < sampleRange.length){
if (sampleRange[sampleLastRow][0] == ""){
break;
}
sampleLastRow++;
};
return sampleLastRow;
})()

How should I add the rows (without the headers) after the last row with data (without overwriting anything in the "Master_db")

The code below is overwriting on the existing data.
#OMila helped me with the original code, I could not articulate exactly what I needed hence starting a new question.
function Dom() {
var origin_sheet = SpreadsheetApp.getActive().getSheetByName('Dom_Sum');
var firstRow = 1;
var firstCol = 1;
var numRows = origin_sheet.getLastRow();
var numCols = 22;
var origin_values = origin_sheet.getRange(firstRow, firstCol, numRows, numCols).getValues();
var dest_values = [];
for(var i = 0; i < origin_values.length; i++) {
if(origin_values[i][0] != '') {
dest_values.push(origin_values[i]);
}
}
var dest_id = "1ZGq7L7bvF1INuDgZxhHnVsihkYkYubmncSAE5uC-Pq4";
var dest_sheet = SpreadsheetApp.openById(dest_id).getSheetByName("Master_Db");
var numRowsDest = dest_values.length;
var dest_range = dest_sheet.getRange(1, 1, numRowsDest, 22);
dest_range.setValues(dest_values);
}
I would like to add the data created in the "Dom_Sum" worksheet below the last row of data in the other workbook with the worksheet name "Master_Db"
#OMila I'm really grateful to you, and if you like we could offer you a consultation fee for future projects. (boseav#gmail.com)
Instead of writing your value into the range dest_sheet.getRange(1, 1, numRowsDest, numCols)
retrieve the last row of your destination sheet and write starting with the next row
var destLastRow=dest_sheet.getLastRow();
var dest_range = dest_sheet.getRange(destLastRow+1, 1, numRowsDest, numCols);
dest_range.setValues(dest_values);

Issues with For and MailApp

I have a code that I have compiled from some other codes but it is not doing quite what I want. The idea is to cycle through each row searching for a keyword (TRUE) and send an email to the email address listed in column A with the message in column B. Unfortunately, I'm not skilled enough to work this through myself.
function findAndSendMail() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Reminder');
var search = "TRUE"
var lastRow = ss.getLastRow();
var range = ss.getRange(1,5,lastRow); //define range for column E
//find all occurrences of "TRUE" in column E and push range to array
var ranges = range.createTextFinder(search).findAll();
var message = '';
//loop through each range
for (i = 0; i < ranges.length; i++) {
var row = ranges[i].getRow();
var lastCol = ss.getLastColumn();
var values = ss.getRange(row, 1, 1, lastCol).getValues(); //get all values for the row
var emailAddress = values[0][0]; //column A
var reminder = values[0][1]; //column B
var sendvalidation = values[0][4]; //column E
if (sendvalidation = true) {
message+=Utilities.formatString("**This is an automated message.**\n\n"+reminder+"\n\n**This is an automated message.**");
}
var subject = 'General Reminder';
if (message) {
MailApp.sendEmail(emailAddress, subject, message);
}
}
}
I want one email for each row with only the information from that row. What I am currently getting is one email with the first row, then another email with the first and second row, then another email with the first, second and third row, etc.
Based on the question, it sounds like you have a spreadsheet and you want it to send the content in col B to the recipient in col A if col E = "TRUE". I'm a bit of a novice myself, but here is how I would approach this situation. What we're doing here is pulling all the data in the spreadsheet into an array, then looping over that array pushing rows into a new array if col E = "TRUE." We then loop over the new array, and send an email for each row with its data.
`function findAndSendMail() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Reminder');
var data = ss.getDataRange().getValues();
var emails = [];
for(var i = 0; i < data.length; i ++) {
// Make sure this points at the column you want to check
if(data[i][4] === "TRUE") {
emails.push(data[i]);
}
}
for(var j = 0; j < emails.length; j ++) {
var row = emails[j];
var emailAddress = row[0];
var reminder = row[1];
if(reminder !== "") {
var message = "**This is an automated message.**\n\n"" + reminder + "\n\n**This
is an automated message.**";
var email = {
to: emailAddress,
subject: "General Reminder",
body: message
};
MailApp.sendEmail(email);
}
}
} `
Figured it out on my own. The code I stole from was set up differently, so I was able to get it to work by removing some conditionals.
function findAndSendMail() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Reminder');
var search = "TRUE"
var lastRow = ss.getLastRow();
var range = ss.getRange(1,5,lastRow); //define range for column E
//find all occurrences of "TRUE" in column E and push range to array
var ranges = range.createTextFinder(search).findAll();
//loop through each range
for (i = 0; i < ranges.length; i++) {
var row = ranges[i].getRow();
var lastCol = ss.getLastColumn();
var values = ss.getRange(row, 1, 1, lastCol).getValues(); //get all values for the row
var emailAddress = values[0][0]; //column A
var reminder = values[0][1]; //column B
var sendvalidation = values[0][4]; //column E
var message = reminder;
var subject = 'General Reminder';
MailApp.sendEmail(emailAddress, subject, "**This is an automated message.**\n\n"+message+"\n\n**This is an automated message.**");
}
}

How to retrieve data from columns dependent upon date

I have a rota (a fixed order of rotation (as of persons or duties)) that I've already had help with this week. It's up & running as is, but for simpler reading I'd like to transpose it.
You can see the transposed sheet as I'd like it here
The current script is for the pre-transposed table.
It would search Column 0 for the date. If it was was 7 days away it would retrieve the name from Column 1 & match it with e-mail address in separate sheet etc.
What I'd like to do is instead have the Date in Row 0 & then subsequent names in Row 1 etc etc
I've tried various things. I've stepped through the code & can see what it's doing, & I've done some reading through about 2 dimensional arrays, but I can't seem to find a way of getting the code to work down through columns, instead of across the rows.
Here's the code:
function sendEmails() {
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var sh1 = ss1.getSheetByName("Rota")
ss1.setActiveSheet(sh1);
var rotalink = "https://docs.google.com/spreadsheets/d/1LgzUWSAGA2kbpar8r5nosU1bSHF7nrtvtUiHS3nB_e8";
var sheet = SpreadsheetApp.getActiveSheet();
// Fetch the range
var dataRange = sheet.getRange("B3:G50")
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var today=new Date();
var timecell = new Date(row[0]);
var timediff = new Date();
var one_day=1000*60*60*24;
var daystogo = Math.ceil((timecell.getTime()-today.getTime())/(one_day));
if (daystogo==7) {//only e-mail people with one week to go. To change that alter the "7" to the number of days you want
var subject = "Rota reminder!";
var emailAddress = [];
var message;
message = "Hello \n\n"+
"You are down to help at Youth Café this week. \n\n" +
"Please see the below rota for your role \n\n" +
"If you have any questions or problems let us know at thameyouthcafe#gmail.com \n\n" +
"Remember, you can check the rota anytime by clicking on the link below: \n\n"+
rotalink
for (var x = 1; x < 5; x++) { // 5 because emails are till col4
// var emailAddress = []; // Start by collecting the non-blank emails in an array
if (getEmailFromName(row[x]) != "") {
emailAddress.push(getEmailFromName(row[x]))
}
}
emailAddress = emailAddress.join(); // Join the array to get a comma separated string
MailApp.sendEmail(emailAddress, subject, message);
}
}
}
and here's the getEmailFromName function that matches with SKey (which I presume comes from the "i" variable in the first function?
function getEmailFromName(sKey) {
// to use this function, don’t put anything in the first column (A) or row (1).
// Put the name (i.e. the key, or what we’re looking for) in column B.
// Put what we want to return in column C.
var columnToSearch = 1; //column B
// Set the active sheet to our email lookup
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var sh1 = ss1.getSheetByName("EmailContactList")
ss1.setActiveSheet(sh1);
var data = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var line = -1;
for( var i = 0; i < data.length; i++ ) {
if( data[i][columnToSearch] == sKey ) {
line = i;
break;
}
}
if( line != -1 ) {
//do what you want with the data on "line"
return data[line][2]; //value on column C of the matched line
}
else {
return "";
// if criteria is not found
}
}
Try it this way:
function sendEmails() {
var ss1 = SpreadsheetApp.getActive();
var sh1 = ss1.getSheetByName("Rota")
ss1.setActiveSheet(sh1);
var rotalink = "https://docs.google.com/spreadsheets/d/1LgzUWSAGA2kbpar8r5nosU1bSHF7nrtvtUiHS3nB_e8";
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange("B3:G50")
var data = dataRange.getValues();
for (var i=0;i<dataRange.length;i++) {
var row = data[i];
var today=new Date();
var timecell = new Date(row[0]);
var timediff = new Date();
var one_day=1000*60*60*24;
var daystogo = Math.ceil((timecell.getTime()-today.getTime())/(one_day));
if (daystogo==7) {
var subject = "Rota reminder!";
var emailAddress = [];
var message = Utilities.formatString('Hello\n\nYou are down to help at Youth Café this week.\n\n Please see the below rota for your role \n\nIf you have any questions or problems let us know at thameyouthcafe#gmail.com \n\nRemember, you can check the rota anytime by clicking on the link below: \n\n%s',rotalink);
for (var x=1;x<5;x++) {
if(data[i][x]) {
emailAddress.push(data[i][x]);
}
}
MailApp.sendEmail(emailAddress.join(), subject, message);
}
}
}
Managed to solve it - thank you for your contributions. Turned out it was incredibly simple.
Just had to change this line:
var timecell = new Date(data[0])
to this:
var timecell = new Date(data[0][i])
so it iterates through the first row of each column.

Categories

Resources