I have script to generate Google Form and set where the Destination Form Response. After set, I want to rename the Sheet Name, from default Response Sheet Name ( eg. Form Response 1), with custom Sheet Name.
function genarateForm() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('CONSUMEN DATA');
var rowNumber = (sheet.getDataRange().getNumRows())-3;
var myQuestions = sheet.getRange(5,2,rowNumber,1).getValues();
var form = FormApp.create('CUSTOMER BILL');
const formTitle = 'BILL REPORT'
form.setTitle(formTitle)
.setDescription('Fill with customer bill :')
.setAllowResponseEdits(true)
.setAcceptingResponses(true);
for(var i=0;i<rowNumber;i++){
var addItem = form.addTextItem();
addItem.setTitle(pertanyaanKu[i]);
}
form.setDestination(FormApp.DestinationType.SPREADSHEET, ss.getId())
// I want to set the sheet destination response with "CUSTOMER BILL"
}
In order to achieve your goal, how about the following modification?
From:
form.setDestination(FormApp.DestinationType.SPREADSHEET, ss.getId())
To:
form.setDestination(FormApp.DestinationType.SPREADSHEET, ss.getId());
// I added the below script.
SpreadsheetApp.flush(); // This might not be required to be used.
const formUrl = form.getEditUrl().replace("edit", "viewform");
const formSheet = ss.getSheets().find(s => s.getFormUrl() == formUrl);
if (formSheet) {
formSheet.setName("CUSTOMER BILL");
}
When this script is run, the sheet name of a sheet of the created Google Form is changed to "CUSTOMER BILL".
Related
function FunctionC12C31() {
var allSheetTabs,i,L,thisSheet,thisSheetName,sheetsToExclude,value;
sheetsToExclude = ['Template','Sheet1','Sheet2'];
var ss = SpreadsheetApp.getActiveSpreadsheet();
allSheetTabs = ss.getSheets();
L = allSheetTabs.length;
for (i=0;i<L;i++) {
thisSheet = allSheetTabs[i];
thisSheetName = thisSheet.getName();
//continue to loop if this sheet is one to exclude
if (sheetsToExclude.indexOf(thisSheetName) !== -1) {continue;}
value = thisSheet.getRangeList(['C12:C35','C5:C6','G16:G19','G4']).clearContent();
}}
Need help modifying this to instead of clearing contents
it will copy the formula from a RangeList(['C12:C35','C5:C6','G16:G19','G4'])
to be copied to from a Template Sheet too all sheet except to "sheetsToExclude" list.
or perhaps a different script?
copy from a template sheet RangeList(['C12:C35','C5:C6','G16:G19','G4'])
data will be formulas and need to be pasted on same RangeList
paste data to ALL sheets except from specified sheets. Like sheetsToExclude = ['Template','Sheet1','Sheet2'];
I believe your goal is as follows.
You want to retrieve the formulas from the cells 'C12:C35','C5:C6','G16:G19','G4' of a template sheet. And, you want to put the retrieved formulas to the same ranges in the sheets except for sheetsToExclude = ['Template','Sheet1','Sheet2'] in the active Spreadsheet.
The template sheet is included in the same active Spreadsheet. The sheet name is "Template".
In this case, how about the following modification?
Modified script 1:
Unfortunately, in the current stage, the values cannot be retrieved and put from the discrete cells using RangeList. So, in this case, it is required to use another method. In order to retrieve the formulas from the discrete cells and put the formulas to the discrete cells with the row process cost, I would like to propose using Sheets API. So, before you use this script, please enable Sheets API at Advanced Google services.
In this script, "Method: spreadsheets.batchUpdate" is used.
function myFunction() {
// These variables are from your showing script.
var templateSheetName = "Template";
var sheetsToExclude = [templateSheetName, 'Sheet1', 'Sheet2'];
var ranges = ['C12:C35', 'C5:C6', 'G16:G19', 'G4'];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssId = ss.getId();
var template = ss.getSheetByName(templateSheetName);
var sheetId = template.getSheetId();
var gridRanges = ranges.map(r => {
var range = template.getRange(r);
var row = range.getRow();
var col = range.getColumn();
return {
sheetId,
startRowIndex: row - 1,
endRowIndex: row - 1 + range.getNumRows(),
startColumnIndex: col - 1,
endColumnIndex: col - 1 + range.getNumColumns(),
};
});
var requests = ss.getSheets().reduce((ar, s) => {
if (!sheetsToExclude.includes(s.getSheetName())) {
gridRanges.forEach(source => {
var destination = JSON.parse(JSON.stringify(source));
destination.sheetId = s.getSheetId();
ar.push({ copyPaste: { source, destination, pasteType: "PASTE_FORMULA" } });
});
}
return ar;
}, []);
Sheets.Spreadsheets.batchUpdate({ requests }, ssId);
}
When this script is run, the formulas are retrieved from 'C12:C35', 'C5:C6', 'G16:G19', 'G4' of templateSheetName sheet, and the retrieved formulas are put into the same ranges in the sheets except for sheetsToExclude.
Modified script 2:
In this script, "Method: spreadsheets.values.batchGet" and "Method: spreadsheets.values.batchUpdate" are used.
function myFunction() {
// These variables are from your showing script.
var templateSheetName = "Template";
var sheetsToExclude = [templateSheetName, 'Sheet1', 'Sheet2'];
var ranges = ['C12:C35', 'C5:C6', 'G16:G19', 'G4'];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssId = ss.getId();
var sheets = ss.getSheets().filter(s => !sheetsToExclude.includes(s.getSheetName()));
var formulas = Sheets.Spreadsheets.Values.batchGet(ssId, { ranges: ranges.map(r => `'${templateSheetName}'!${r}`), valueRenderOption: "FORMULA" }).valueRanges;
var data = sheets.flatMap(s => formulas.slice().map(({ range, values }) => ({ range: range.replace(templateSheetName, s.getSheetName()), values })));
Sheets.Spreadsheets.Values.batchUpdate({ data, valueInputOption: "USER_ENTERED" }, ssId);
}
When this script is run, the formulas are retrieved from 'C12:C35', 'C5:C6', 'G16:G19', 'G4' of templateSheetName sheet, and the retrieved formulas are put into the same ranges in the sheets except for sheetsToExclude.
Note:
If you cannot use Sheets API, how about the following modified script? In this case, only the Spreadsheet service (SpreadsheetApp) is used.
function myFunction2() {
// These variables are from your showing script.
var templateSheetName = "Template";
var sheetsToExclude = [templateSheetName, 'Sheet1', 'Sheet2'];
var ranges = ['C12:C35', 'C5:C6', 'G16:G19', 'G4'];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssId = ss.getId();
var sheets = ss.getSheets().filter(s => !sheetsToExclude.includes(s.getSheetName()));
var formulas = ranges.map(r => ss.getSheetByName(templateSheetName).getRange(r).getFormulas());
sheets.forEach(s => ranges.forEach((r, i) => s.getRange(r).setFormulas(formulas[i])));
}
References:
Method: spreadsheets.batchUpdate
Method: spreadsheets.values.batchGet
Method: spreadsheets.values.batchUpdate
I have a Google Form that does two things upon hitting the Submit button. First, it dumps that data into a Spreadsheet, then it autofills a Google Doc Template with the info from the Form.
In my script to autofill the Google Doc, I've grabbed the URL for the Google Doc. But I need to write this URL into the last row of Column J in my Google Sheet. Correction: using the getActiveSheet functions are fine, I forgot this script is running from the (Active) Google Sheet (apologies!).
Can anyone assist with this? Here's a snippet of the script to get the URL:
function autoFillGoogleDocFromForm(e) {
//e.values is an array of form values
var TimeStamp = e.values[0];
var Technician = e.values[1];
var Vendor = e.values[2];
var xxx = e.values[3];
var yyy = e.values[4];
var SerialNumber = e.values[5];
var AssetTag = e.values[6];
var TicketNumber = e.values[7];
var HostName = e.values[8];
var DocumentLink = e.values[9];
var Return = e.values[10];
var Platform = e.values[11];
var Summary = e.values[12];
var URL = "";
//file is the template file, and you get it by ID
var file = DriveApp.getFileById('aaa');
//Put auto filled Google Doc into the appropriate Vendor Folder
//file.makeCopy will return a Google Drive file object
if (Vendor == "111") {
var folder = DriveApp.getFolderById('bbb')
var copy = file.makeCopy(TicketNumber + ' - ' + SerialNumber, folder);
}
if (Vendor == "222") {
var folder = DriveApp.getFolderById('ccc')
var copy = file.makeCopy(TicketNumber + ' - ' + SerialNumber, folder);
}
if (Vendor == "333") {
var folder = DriveApp.getFolderById('ddd')
var copy = file.makeCopy(TicketNumber + ' - ' + SerialNumber, folder);
}
//Once we've got the new file created, we need to open it as a document by using its ID
var doc = DocumentApp.openById(copy.getId());
//Get the url of the newly created Google Doc
var url = doc.getUrl();
//Script to write this URL into the Shared Google Sheet will go here
//Since everything we need to change is in the body, we need to get that
var body = doc.getBody();
//Then we call all of our replaceText methods
body.replaceText('{{EmailAddress}}', Technician);
body.replaceText('{{TicketNumber}}', TicketNumber);
body.replaceText('{{HostName}}', HostName);
body.replaceText('{{SerialNumber}}', SerialNumber);
body.replaceText('{{AssetTag}}', AssetTag);
body.replaceText('{{Summary}}', Summary);
body.replaceText('{{Vendor}}', Vendor);
body.replaceText('{{URL}}', url);
//Lastly we save and close the document to persist our changes
doc.saveAndClose();
Thanks in advance!
From your following situation in your question,
Also this is a shared Google Sheet, so I can't use the getActiveSheet function, I'd need to reference the Google Sheet URL, I believe.
If you have the permission to write the values to the shared Google Spreadsheet, how about the following modification?
From:
var url = doc.getUrl();
//Script to write this URL into the Shared Google Sheet will go here
To:
var url = doc.getUrl();
//Script to write this URL into the Shared Google Sheet will go here
var sheet = SpreadsheetApp.openById("### Spreadsheet ID ###").getSheetByName("### sheet name ###");
sheet.appendRow([url]);
In this modification, please set the Spredsheet ID and sheet name. By this, the value of url is appended to the next row of the last row of the sheet in the Google Spreadsheet.
If you want to use the Spreadsheet URL instead of Spreadsheet ID, please modify openById("### Spreadsheet ID ###") to openByUrl("### Spreadsheet URL ###").
References:
openById(id)
openByUrl(url)
appendRow(rowContents)
Edit:
From the following replying,
That doesn't seem to work to insert the URL into the last row of column J unfortunately. It looks like this script can use the Active Sheet afterall, I'll edit the OP.
In this case, how about the following modification?
From:
var url = doc.getUrl();
//Script to write this URL into the Shared Google Sheet will go here
To:
var url = doc.getUrl();
//Script to write this URL into the Shared Google Sheet will go here
// var sheet = SpreadsheetApp.openById("### Spreadsheet ID ###").getSheetByName("### sheet name ###");
var sheet = SpreadsheetApp.getActiveSheet(); // or SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheetname")
sheet.getRange("J" + (sheet.getLastRow() + 1)).setValue(url);
Or
var url = doc.getUrl();
//Script to write this URL into the Shared Google Sheet will go here
// This is from https://stackoverflow.com/a/44563639/7108653
Object.prototype.get1stEmptyRowFromTop = function (columnNumber, offsetRow = 1) {
const range = this.getRange(offsetRow, columnNumber, 2);
const values = range.getDisplayValues();
if (values[0][0] && values[1][0]) {
return range.getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow() + 1;
} else if (values[0][0] && !values[1][0]) {
return offsetRow + 1;
}
return offsetRow;
};
// var sheet = SpreadsheetApp.openById("### Spreadsheet ID ###").getSheetByName("### sheet name ###");
var sheet = SpreadsheetApp.getActiveSheet(); // or SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheetname")
sheet.getRange("J" + sheet.get1stEmptyRowFromTop(10)).setValue(url);
Suggestion:
If you need to write the URL value into the last row of Column J in a shared Google Spreadsheet file, you can try this sample below:
function sample() {
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/SHEET_ID_IS_HERE/edit#gid=0');
var sheet = ss.getSheets()[0]; // access first sheet
var activeSheet = ss.setActiveSheet(sheet);
//Sample setValue() action to the shared sheet file
activeSheet.getRange("A1").setValue("URL");
}
NOTE: You would need to have an editor permission on the Shared Google Sheet file that you're accessing
References:
openByUrl(url)
getSheets()
setActiveSheet(sheet)
Here's the code that ended up working for me.
//Get the url of the newly created Google Doc
var url = doc.getUrl();
// var sheet = SpreadsheetApp.openById("### Spreadsheet ID ###").getSheetByName("### sheet name ###");
var sheet = SpreadsheetApp.getActiveSheet(); // or SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheetname")
sheet.getRange("J" + (sheet.getLastRow())).setValue(url);
and thanks for the help. I've got a noob question, and need a noob answer.
Trying to email a specific google sheet as a pdf weekly, but script emails out whatever sheet happens to be open at the time.
Stole various snippets of code, here's what I've got: (And no, I don't think that this block of code was formatted and posted correctly.)
function endOfWK_1 () {
//This script converts all formulas to values in the currently displayed sheet, then converts the currently displayed sheet to a pdf, then emails the
pdf as an attachment to the addresses shown in cell B17 in the "Email" sheet.
//Replace all formulas in range "WK 1!A6:A29" with values
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('WK 1');
var range = sheet.getRange("WK 1!A6:A29");
range.copyTo(range, {contentsOnly: true});
// FOR WK1 ONLY!!!
// Set the Active Spreadsheet so we don't forget
var originalSpreadsheet = SpreadsheetApp.getActive();
// Set the message to attach to the email.
var message = "Please see attached.";
// Get Dates from Email!B5
var period = originalSpreadsheet.getRange("Email!B5").getValues();
// Construct the Subject Line
var subject = period;
// Get contact details from "Email" sheet and construct To: Header
var contacts = originalSpreadsheet.getSheetByName("Email");
var numRows = contacts.getLastRow();
var emailTo = contacts.getRange(17, 2, numRows, 1).getValues();
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var projectname = SpreadsheetApp.getActiveSpreadsheet();
sheet = originalSpreadsheet.getActiveSheet();
sheet.copyTo(newSpreadsheet);
// Find and delete the default "Sheet1"
newSpreadsheet.getSheetByName('Sheet1').activate();
newSpreadsheet.deleteActiveSheet();
// Create the PDF, currently called "Tracking Sheet.pdf"
var pdf = DriveApp.getFileById(newSpreadsheet.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:'Tracking Sheet.pdf',content:pdf, mimeType:'application/pdf'};
// Send the freshly constructed email
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
// Delete the sheet that was created
DriveApp.getFileById(newSpreadsheet.getId()).setTrashed(true);
// Write the date and time that the script ran
var date = sheet.getRange('Statistics!A1').getValues();
SpreadsheetApp.getActiveSheet().getRange('Analysis!E5').setValues(date);
}
This is a bound script, attached to a google workbook containing 5 sheets. My problem is that my script always emails the sheet that happens to be open at the time.
I want to email one specific sheet, whether the workbook is open or closed. How can I do this? (I hope to install a trigger to make this script run automatically.)
Also, anyone want to critique my code?
Thanks to all.
I've fixed it up a little and added some comments. There were a lot of little things I fixed up biggest thing was that you should reuse variables that you've created.
This hasn't been tested...
function endOfWK_1 () {
//Replace all formulas in range "WK 1!A6:A29" with values
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetWK1 = activeSpreadsheet.getSheetByName('WK 1');
var range = sheetWK1.getRange("WK 1!A6:A29");
range.copyTo(range, {contentsOnly: true});
// FOR WK1 ONLY!!!
// Set the Active Spreadsheet so we don't forget
var originalSpreadsheet = SpreadsheetApp.getActive(); //this should probably be changed depending on what sheet you are trying to access: activeSpreadsheet.getSheetByName('Email')
// Set the message to attach to the email.
var message = "Please see attached.";
// Get Dates from Email!B5
var period = originalSpreadsheet.getRange("Email!B5").getValues();
// Construct the Subject Line
var subject = period;
// Get contact details from "Email" sheet and construct To: Header
var contacts = originalSpreadsheet.getSheetByName("Email");
var numRows = contacts.getLastRow();
var emailTo = contacts.getRange(17, 2, numRows, 1).getValues();
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export"); //Create a spreadsheet to copy to
// var originalSheet = activeSpreadsheet.getSheetByName("WK1"); Already defined above as sheetWK1
//var projectname = SpreadsheetApp.getActiveSpreadsheet(); Seems like this is not used.
sheetWK1.copyTo(newSpreadsheet); //Take the original sheet and copy it to the newSpreadsheet
// Find and delete the default "Sheet1"
newSpreadsheet.deleteSheet(newSpreadsheet.getSheetByName("Sheet1")); //We can just call the deleteSheet method.
// Create the PDF, currently called "Tracking Sheet.pdf"
var pdf = newSpreadsheet.getAs('application/pdf').getBytes(); //No need to get the Spreadsheet object again, as we alreat have it!
var attach = {fileName: 'Tracking Sheet.pdf', content: pdf, mimeType: 'application/pdf'};
// Send the freshly constructed email
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
// Delete the sheet that was created
newSpreadsheet.setTrashed(true); //Again no need to find the object. We have it.
// Write the date and time that the script ran
var date = sheet.getRange('Statistics!A1').getValues();
activeSpreadsheet.getRange('Analysis!E5').setValues(date);
}
The main issue was var originalSpreadsheet = SpreadsheetApp.getActive(); you are getting the active sheet and using that to create you pdf.
EDIT: I've cleaned up the whole thing a little and ended up with this. It hasn't been tested.
function endOfWK_1 () {
//Replace all formulas in range "WK 1!A6:A29" with values
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetWK1 = activeSpreadsheet.getSheetByName('WK 1');
var emailSheet = activeSpreadsheet.getSheetByName("Email");
var range = sheetWK1.getRange("WK 1!A6:A29");
range.copyTo(range, {contentsOnly: true});
// FOR WK1 ONLY!!!
// Set the message to attach to the email.
var message = "Please see attached.";
// Get Dates from Email!B5
var period = emailSheet.getRange("Email!B5").getValues();
// Construct the Subject Line
var subject = period;
// Get contact details from "Email" sheet and construct To: Header
var numRows = emailSheet.getLastRow();
var emailTo = emailSheet.getRange(17, 2, numRows, 1).getValues();
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
sheetWK1.copyTo(newSpreadsheet);
// Find and delete the default "Sheet1"
newSpreadsheet.deleteSheet(newSpreadsheet.getSheetByName("Sheet1"));
// Create the PDF, currently called "Tracking Sheet.pdf"
var pdf = newSpreadsheet.getAs('application/pdf').getBytes();
var attach = {fileName: 'Tracking Sheet.pdf', content: pdf, mimeType: 'application/pdf'};
// Send the freshly constructed email
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
// Delete the sheet that was created
DriveApp.getFileById(newSpreadsheet.getId()).setTrashed(true);
// Write the date and time that the script ran
var date = activeSpreadsheet.getRange('Statistics!A1').getValues();
activeSpreadsheet.getRange('Analysis!E5').setValues(date);
}
I used Google's Quickstart: Add-on for Google Forms to enable e-mail notifications for respondents of my form. I also added a few lines to send unique code to each respondent and I would like to have these codes stored in responses sheet.
The code below sends the message with code, but it doesn't store code in responses sheet.
function sendRespondentNotification(response) {
var form = FormApp.getActiveForm();
var settings = PropertiesService.getDocumentProperties();
var emailId = settings.getProperty('respondentEmailItemId');
var emailItem = form.getItemById(parseInt(emailId));
var respondentEmail = response.getResponseForItem(emailItem)
.getResponse();
if (respondentEmail) {
var template =
HtmlService.createTemplateFromFile('RespondentNotification');
template.paragraphs = settings.getProperty('responseText').split('\n');
template.kod = (new Date).getTime().toString(16).substring(5);
template.notice = NOTICE;
var message = template.evaluate();
MailApp.sendEmail(respondentEmail,
settings.getProperty('responseSubject'),
message.getContent(), {
name: form.getTitle(),
htmlBody: message.getContent()
});
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var LastRow = sheet.getLastRow();
var cell = sheet.getRange(LastRow, 5);
cell.setValue(template.kod);
}
}
you could use onFormSubmit to generate the unique id and include it in the email for a webapp to use. that id could be something simple like the row number of the response (not in e.values thou) or generate on the fly and write to the responses spreadsheet as a new column. adding columns does not break the form.
In class Spreadsheet there is getFormUrl() which returns the url for the form attached to the spreadsheet, null if there is no form.
But now that you can have a form attached to each sheet, how do you get the ID or Url of the form attached to a given sheet?
You can call getFormUrl on the Spreadsheet, and on each Sheet of the Spreadsheet:
let ss = SpreadsheetApp.getActiveSpreadsheet();
let sheets = ss.getSheets();
for (let sheet of sheets) {
let sheetName = sheet.getName();
let formUrl = sheet.getFormUrl();
Logger.log("formUrl1 %s %s", sheetName, formUrl);
if (formUrl) {
Logger.log("formid1 %s", FormApp.openByUrl(formUrl).getId());
}
}
let formUrl = ss.getFormUrl();
Logger.log("formUrl2 %s", formUrl);
if (formUrl) {
Logger.log("formid2 %s", FormApp.openByUrl(formUrl).getId());
}
In my case, the spreadsheet was created by a form (in the Answers section, the green spreadsheet icon), and formUrl2 refers to this form. The formUrl1 of one of the sheets relates also to this form, because this sheet contains the answers of the form. Another sheet has the url of a second Form, because I connected the second form to the same spreadsheet. A third sheet has null as formUrl, because it is not related to a form.
I give an example for you of my script.
Maybe it can help you.
example :
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Sheet1");
var data = ss.getDataRange().getValues(); // Data for pre-fill
var formUrl = ss.getFormUrl(); // Use form attached to sheet
var form = FormApp.openByUrl(formUrl);
var items = form.getItems();
I just took the URL provided by the getFormUrl and assigned letters 49 through 93 to a string. That should provide the Form ID.
var ss=SpreadsheetApp.getActiveSpreadsheet();
var fOrmUrl=ss.getFormUrl();
var sTring="";
for (var i=49; i<93; i++)
{
sTring=sTring + fOrmUrl[i];
}
I've noticed that the sheet.getFormURL() method does not always return the same URL that form.getPublishedUrl() returns. Both URLs are valid, though. To get around the problem, I'm opening the sheet's formUrl and then checking and comparing that form's ID:
var form = FormApp.getActiveForm();
var formId = form.getId();
const matches = spreadSheet.getSheets().filter(function (sheet) {
var sheetFormUrl = sheet.getFormUrl();
if (sheetFormUrl){
return FormApp.openByUrl(sheetFormUrl).getId() === formId;
}
});
const sheet = matches[0]