Dynamically Generate Questions in Google Forms Without Creating New Columns - javascript

I'm trying to create a Google Form where a question is dynamically generated by a script.
The form is designed to capture the results of product inspections, which can either result in a pass or a fail. The inspections are raised as the result of a product issue, and continue on for a certain period of time until the issue is resolved - at which point they are closed.
I currently have the form set up as a web app, which will generate a multiple choice grid item upon opening based on the inspections that are currently required.
The form pulls in all of the currently active inspections from the linked spreadsheet, and generates the question options based on this data. However, the script is creating a new set of columns every time the form is opened, even if many of them are the same inspection.
Is there a way to only generate a new column if the question added is new? And if the question is not new, can the responses for this question be funneled into the original column on the spreadsheet?
Thanks.
function doGet(){
var form = FormApp.openById("###");
var workBook = SpreadsheetApp.openById("###");
var sheet = workBook.getSheetByName("###");
var range = "A:B";
var options2DArr = sheet.getRange(range).getValues();
var options = [];
for (var i = 0; i < options2DArr.length; i++)
{
if (options2DArr[i][0] != "")
{
options.push(options2DArr[i][1] + " (" + options2DArr[i][0] + ")");
}
}
myCheckBoxItem = form.getItemById("###").asGridItem();
currentRows = myCheckBoxItem.getRows();
myCheckBoxItem.setTitle('Inspection Results')
.setRows(options)
.setColumns(['Pass', 'Fail']);
var URL = form.getPublishedUrl();
// redirect to the prefilled form URL dynamically created above
return HtmlService.createHtmlOutput("<script>window.top.location.href=\"" + URL + "\"</script>");
}

Related

when attempting to use e.value in google sheet script I get TypeError: Cannot read property "Values" from undefined. (line 7, file "Code")

This is a two part question:
I have google sheet with a linked Form. When the form is submitted I want the responses from the form to be copied to another google sheet where I intend to change and reformat and then send via email. The script below is what i have currently written and it has a trigger set up onFormSubmit. However, I keep getting the follow error:
TypeError: Cannot read property "Values" from undefined. (line 7, file "Code")
Code below:
function formSubmitReply(e)
{
var t = "1g-wIs6nGxu3mJYA1vKtPCxBLCsvh1upeVGbCokOOTIw";
var tName = "AggregationOutput";
//Get information from form and set as variables
var email = e.Values[2];
var name = e.Values[3];
// Get template, copy it as a new temp, and save the Doc’s id
var tcopyId = SpreadsheetApp.openById(t).copy(tName+' for '+name).getId();
// Open the temporary document & copy form responses into template copy response sheet
var copyt = SpreadsheetApp.openById (tcopyId);
var copyts = copyt.getSheetByName('Resp');
// Transfers Data from Form Responses to Temporary file
copyts.getRange('A3').setValue(name);
//Sends copy of template in an email as an excel file
var url = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + copyt.getId();
var subject = 'Aggregaton Output for' + name;
var body = url
MailApp.sendEmail(email, subject, body);
// Deletes temp file
DriveApp.getFileById(tcopyId).setTrashed(true);
}
Part two of my question, even if I can get the code to work what would you recommend when a question is skipped in the form - won't this change the array from e.values. The issue with using the last row as a problem is that I want people to go back and edit responses on the form and then resubmit which means the last row isn't always the row used.
Any and all help is appreciated.
For Part 1, try this:
function formSubmitReply(e)
{
var t = "1g-wIs6nGxu3mJYA1vKtPCxBLCsvh1upeVGbCokOOTIw";
var tName = "AggregationOutput";
//Get information from form and set as variables
var itemResponses = e.response.getItemResponses();
var email = itemResponses[2].getResponse();
var name = itemResponses[3].getResponse();
// Get template, copy it as a new temp, and save the Doc’s id
var tcopyId = SpreadsheetApp.openById(t).copy(tName+' for '+name).getId();
// Open the temporary document & copy form responses into template copy response sheet
var copyt = SpreadsheetApp.openById (tcopyId);
var copyts = copyt.getSheetByName('Resp');
// Transfers Data from Form Responses to Temporary file
copyts.getRange('A3').setValue(name);
//Sends copy of template in an email as an excel file
var url = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + copyt.getId();
var subject = 'Aggregaton Output for' + name;
var body = url
MailApp.sendEmail(email, subject, body);
// Deletes temp file
DriveApp.getFileById(tcopyId).setTrashed(true);
}
Question 1:
The error you get is due to a wrong syntax, values (All small, not Values)
var email = e.values[2];
var name = e.values[3];
Question 2:
When the question is skipped the value of the response is blank. So if an email is left blank e.values[2] would still refer to the email field in your form, but will have no value in it.
If you have edit later option activated on the form, the edited responses will only be present in the e.values array. So if they update their email ID only, e.values[2] = "updated Email ID" and e.value[0-1,3-end] = Empty/blank.
To figure out if the submission is new entry or edited entry you can use e.range to figure out where the responses are going to be added in the "form Response" sheet. And you can mirror that range in your "resp" sheet to keep it updated the same way as form response sheet.

Google Sheets Script only working on one file

I am trying to have the google forms on our website auto-notify us when a user completes the form and then return the data that they entered in a concise email. I do not like the way google notifies you it simply links to you the form to view the response. I searched online and found this code:
function sendFormByEmailPrayer(e)
{
// Remember to replace XYZ with your own email address
var email = "admin#communionchapelefca.org";
// Optional but change the following variable
// to have a custom subject for Google Docs emails
var subject = "Prayer Form Form Submitted";
// The variable e holds all the form values in an array.
// Loop through the array and append values to the body.
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var urlToDoc = SpreadsheetApp.getActive().getUrl();
var body = "";
body = body + "Link to Document: " + urlToDoc;
var message = body + "\n\n" + "";
// Credit to Henrique Abreu for fixing the sort order
for(var i in headers)
message += headers[i] + ' = '+ e.namedValues[headers[i]].toString() + "\n\n";
// This is the MailApp service of Google Apps Script
// that sends the email. You can also use GmailApp here.
MailApp.sendEmail(email, subject, message);
// Watch the following video for details
// http://youtu.be/z6klwUxRwQI
// By Amit Agarwal - www.labnol.org
}
On Form Submit screenshot:
It works great on my one form, but when I copied and pasted this working code to our other 6 forms, it does not work at all. How do I get this to work across our 7 forms? Thanks in advance.
Well I found a better solution than the code presented above. If you use the new Google Forms you can add an "add-on" (YourForm-->Three Dots in top right-->Add-ons).
From there look for "Simply Send" it will auto email a response with headers. Took me about 5 seconds to setup each of my forms.

GridMvc get id attributes from other pages in a paged Grid

I am using GridMvc to show data from database. GridMvc provide filter and sorting grid which is very useful. But now I meet a problem: I want to use JQuery to get a list of id attributes and pass this list to backend. But the Grid is Paged with 30 records per page. So I can only get a list of 30 ids from Page 1. Here is the paged grid:
What I want to do is get all href values(e.g. get a list of XX from page div). And when user trigger Export button, I define an JS Export function:
$('#Export').click(function () {
//Todo: Select all data from front end. Send a list to backend.
var Items = new Array();
var hrefs = new Array();
$('.pagination li').each(function () {
hrefs.push($(this).find('a').attr('href'));
});
var i = 0;
//var items = DeleteItems();
while (i < hrefs.length) {
//redirected to different pages
document.location.href = '/GridView' + hrefs[i];
//Save data
$('#PCA-grid table').find('.grid-row').each(function (index, item) {
//Find target items
var id;
var $checkbox = $(this).find('.DeleteSelected:first');
//Set a for loop here to
if (!$checkbox.is(':checked')) {
id = Number($checkbox.attr('id'));
if (id != NaN) {
Items.push(id);
}
}
});
i++;
}
//Sent list of ids to backend. Using URL redirect
window.location.replace('/GridView/Export?items=' + Items);
});
The basic thought has been described in code above. What I want to do is get urls from page tag. In while loop, try to redirect to target page and then push id attributes in this page to Items Array. But when I debut using Chrome tool, the while loop is not working as expected. There is no redirection happens.
Am I wrong with this problem? I just want to get id attributes from all pages in current grid and then pass this Items Array to backend. So anyone help me?
As far as I considered, it's hard to get all id attributes that needed to be downloaded with paging in grid. What I did was redirecting page to another view. In that view, I hidden same grid with no paging. And sent ids needed to be downloaded from grid to backend, then generated file for client user.
Not sure whether this way is best practice. But I used this method solved this problem.

Getting form's parent data with ajax / javascript

In CRM DYNAMICS 2013, I'm trying to get the contents of a few text fields of a parent form, after a user opens a child form.
On the OnLoad event of the child form, I have this code:
var objvsdsassignedto = document.parentWindow.parent.parent.opener.Xrm.Page.data.entity.attributes.get("address1_line1");
The error I get is:
I have also tried:
var objvsdassignedto = window.top.opener.Xrm.Page.getAttribute("address1_line1").getValue();
The error I get is:
How do I get the contents of fields using the child form?
here's a larger version of the screenshot above: http://screencast.com/t/KHrtREYn3tL
Just wanted to update this question with more of the things I've tried:
var objvsdsassignedto = window.parent.Xrm.Page.data.entity.attributes.get("address1_line1").getValue();
var objvsdsassignedto = document.parentWindow.parent.parent.opener.Xrm.Page.data.entity.attributes.get("address1_line1");
var objvsdsassignedto = window.top.opener.Xrm.Page.getAttribute("address1_line1").getValue();
var objvsdsassignedto = parent.window.Xrm.Page.data.entity.attributes.get("address1_line1").getValue();
var objvsdsassignedto = window.parent.Xrm.Page.getAttribute("address1_composite");
var parentWindow = window.dialogArguments;
alert( parentWindow.Xrm.Page.data.entity.attributes('address1_composite').getValue());
var parentForm = window.top.opener.parent.Xrm.Page.getAttribute("address1_composite").getValue();
alert(parent.window.Xrm.Page.getAttribute('address1_line1').getValue());
var title = window.parent.opener.Xrm.page.ui.controls.getAttribute('address1_composite').getValue();
alert(title);
Are you sure that you can't do that with a simple mapping in the relationship tab? At the end of the day you are creating a lead from an account, so if you want to move a field you should be able to do that via data mapping. Open the solution go into account open the N:1 relationship node, select the relationship to lead and add the fields you want to map, It should be fairly easy without using any js.
After around 10 hours of googling, I've decided to go with cookies: http://www.quirksmode.org/js/cookies.html

Issue with creating an "old-fashioned" mail merge with Google Apps Script

This is a followup to a question I asked yesterday on the Google Apps Script Office Hours Hangout.
The goal of my final script is to create an election process for student elections at the high school where I work using Google Forms. The script has three parts: 1) Create Unique "Voting IDs" (a random 6-digit code) 2) Merge the student data (Name, Homeroom, & Voting ID) on with a template document that will create specific voting instruction for each student. (i.e. an old-fashioned mail merge) 3) Verify the results by checking Voting ID's and removing duplicate votes.
The part of the script that I am having trouble with is the student data merge (step 2). The first dataset is the only one that works. The rest show up as "DocumentBodySection". I have a feeling it is either how I am copying the text from the Document Template or how I am adding the text to the new document.
Spreadsheet w/ Data: https://docs.google.com/spreadsheet/ccc?key=0AierVcXWELCudFI1LU10RnlIVHNsUm11a0dDWEV6M1E
Document Template: (see followup comment for url)
Document Created by Script: https://docs.google.com/document/d/12r2D9SpIVmQYVaasMyMWKjHz6q-ZZyIMEBGHTwlQct8/edit
//Get Settings & Data
ss = SpreadsheetApp.getActiveSpreadsheet();
source_sheet = ss.getSheetByName("Student Data");
settings_sheet = ss.getSheetByName("SETTINGS");
results_column = settings_sheet.getRange("B19").getValue();
source_column = settings_sheet.getRange("B18").getValue();
source_lastrow = source_sheet.getLastRow();
docTemplateID = settings_sheet.getRange("B13").getValue();
docCopyName = settings_sheet.getRange("B14").getValue();
//Merge Student Data with Document
function SendDataMerge () {
// Open docTemplate and Copy Contents to entryTemplate
var docTemplate = DocumentApp.openById(docTemplateID);
var entryTemplate = docTemplate.getActiveSection();
docTemplate.saveAndClose();
// Make a NEW copy of docTemplate
var docTemplate = DocsList.getFileById(docTemplateID);
var docCopy = DocsList.copy(docTemplate, docCopyName);
var docCopyID = docCopy.getId();
// Create Array of Student Data (First, Last, Grouping, VID)
var data = source_sheet.getRange("A2:D"+source_lastrow).getValues();
// Open docCopy for Editing & Clear Contents
var doc = DocumentApp.openById(docCopyID);
var docText = doc.editAsText();
// Run through Student Data
for(var i=0; i<5 /*data.length*/; i++) { //For testing, limit this to 5 entries
var lastName = data[i][0];
var firstName = data[i][1];
var grouping = data[i][2];
var vid = data[i][3];
docText.replaceText('keyLastName', lastName);
docText.replaceText('keyFirstName', firstName);
docText.replaceText('keyGrouping', grouping);
docText.replaceText('keyVID', vid);
docText.appendText('\n*** Appended Text (End of entry) ***');
docText.appendText(entryTemplate);
}
// Save and Close
doc.saveAndClose();
}
I worked around this issue by creating a copy of the template, doing the text replacement and then appending the template elements from the original document into the copy. In particular, I used: var copyTables = templateDoc.getTables(); to fetch and store the tables (as all of my template data was contained in a table) and copyDoc.appendTable(copyTables[0].copy() ); to append the copy (the .copy() at the end seems to work the real magic). This provides the flexibility of updating the template in the friendly Documents interface without having to see a programmer.
I think the problem is with this line:
docText.appendText(entryTemplate);
The variable entryTemplate holds a DocumentBodySection, which is why you are seeing that in the output. If you are trying to append another copy of the original template text you'll need to store that before you enter the loop.
I agree with Eric that appendText(entryTemplate) isn't going to do what you want it to do.
Since you're trying to create one large document with all the students, using a "template" and replacing the text isn't going to work well. I'd suggest instead, creating the "template" in code using the api calls that produce the formatting you want. Then it makes it simple to keep appending new pages of student instructions. Although I think you may run into slowness when the document gets large... I don't know how many students you have.

Categories