I'm working on a script that takes my Google Forms data and performs a replace function on a predetermined template Doc file using body.replaceText which is working fine. I've copied a truncated version of that below.
I can submit a form and it will replace the values of the template as designed but there are some multiple-choice (Yes or No) questions that are represented by checkboxes on the template Doc.
I've figured out how to Logger.log the checkboxes via unicode but how do I get var systemOperational.getValue = "yes" to assign a value to var systemOperationalYes using IF/Else?
Trying to have "If systemOperational value is Yes then systemOperationalYes = unicode \u2611 Else systemOperationalYes = unicode \u2610".
Pardon me if any of this sounds amateur. This is literally my first go at this.
//e.values is an array of form values
var timestamp = e.values[0];
var emailAddress = e.values[1];
var jobID = e.values[2];
var storeName = e.values[3];
var systemOperational = e.values[22];
if (systemOperational.getValue = "yes") {
var systemOperationalYes = "\u2611";
Logger.log("\u2611");
} else {
var systemOperationalYes = "\u2610";
Logger.log("\u2610");
}
// Locat template file
var files = DriveApp.getFolderById("XXXXXXX").searchFiles('title contains "'+ jobID +'"');
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getId());
}
//file is the template file, and you get it by ID
var templateFile = DriveApp.getFileById(file.getId());
//We can make a copy of the template, name it, and optionally tell it what folder to live in
//file.makeCopy will return a Google Drive file object
var responseFolder = DriveApp.getFolderById("XXXXXXXXX");
//Converts dateSigned var to MM-dd-yyyy for use in file name
var convertedDate = new Date(dateSigned);
Logger.log(convertedDate);
var formatSignDate = Utilities.formatDate(convertedDate, "GMT-5", "MM-dd-yyyy");
Logger.log(formatSignDate);
var folder = responseFolder.createFolder(storeName + '-' + jobID + '-' + formatSignDate);
var copy = templateFile.makeCopy(storeName + '-' + jobID + '-' + formatSignDate, 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());
//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('{{SYSOPY}}', systemOperationalYes);
//Lastly we save and close the document to persist our changes
doc.saveAndClose();
// Convert temporary document to PDF
var pdf = DriveApp.getFileById(copy.getId()).getAs("application/pdf")
var url = DriveApp.getFolderById(folder.getId()).createFile(pdf);
// Delete temp file
//DriveApp.getFileById(templateFile.getId()).setTrashed(true);
}```
try it this way:
var timestamp = e.values[0];
var emailAddress = e.values[1];
var jobID = e.values[2];
var storeName = e.values[3];
var systemOperationalYes;
if (e.values[22] = "yes") {
systemOperationalYes = "\u2611";
Logger.log("\u2611");
} else {
systemOperationalYes = "\u2610";
Logger.log("\u2610");
}
Related
Yo!
This is my code that uses the last line of a spreadsheet to generate a google docs, in addition, it places a link to this document in the source spreadsheet. Is it possible to create code that does this for all rows in a worksheet? I'm having trouble using .range() to read the lines individually. The reason for this is simply to maintain and update generated versus updated data.
In advance, thank you!
var app=SpreadsheetApp.openById("Google ID");
var sheet=app.getSheetByName('Respostas ao formulário 1')
function autoFillLastRow() {
var range=sheet.getDataRange().getValues();
var elem = range.pop();
//e.values is an array of form values
var timestamp = elem[0];
//conversor de datas
let data = new Date(timestamp);
let dataFormatada = ((data.getDate() )) + "/" + ((data.getMonth() + 1)) + "/" + data.getFullYear();
var firstName = elem[1];
var lastName = elem[2];
var title = elem[3];
//file is the template file, and you get it by ID
var file = DriveApp.getFileById('Google Drive ID');
//We can make a copy of the template, name it, and optionally tell it what folder to live in
//file.makeCopy will return a Google Drive file object
var folder = DriveApp.getFolderById('Google Drive ID')
var copy = file.makeCopy(dataFormatada + ', ' + firstName, 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());
//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('{{Nome}}', firstName);
body.replaceText('{{Sobrenome}}', lastName);
body.replaceText('{{Título}}', title);
//Lastly we save and close the document to persist our changes
doc.saveAndClose();
//edit cell
var coluna = 5;
var linha = sheet.getLastRow();
var docId = doc.getId();
sheet.getRange(linha, coluna,1,1).setValue("https://docs.google.com/document/d/" + docId);
}
Create document for every row of spreadsheet
function createDocforEveryRowofSpreadsheet() {
var ss = SpreadsheetApp.openById("Google ID");
var sh = ss.getSheetByName('Respostas ao formulário 1')
var file = DriveApp.getFileById('Google Drive ID');
var folder = DriveApp.getFolderById('Google Drive ID')
var [hA,...vs] = sh.getDataRange().getValues();
vs.forEach((r,i) => {
var ts = r[0];
let data = new Date(ts);
let dataFormatada = Utilities.formatDate(new Date(ts), Spreadsheet.getSpreadsheetTimeZone(), "dd/MM/yyyy")
var firstName = r[1];
var lastName = r[2];
var title = r[3];
var copy = file.makeCopy(dataFormatada + ', ' + firstName, folder);
var doc = DocumentApp.openById(copy.getId());
var body = doc.getBody();
body.replaceText('{{Nome}}', firstName);
body.replaceText('{{Sobrenome}}', lastName);
body.replaceText('{{Título}}', title);
doc.saveAndClose();
})
}
I have this code. I want to loop through the array and create a new doc for each entry. If I manually set the loop length to the number of rows it works fine. I want to set it to loop for the length of the array. However the .length property always returns null. What am I missing. I have also tried for each loops with no luck.
function createDocument()
{
//var headers = Sheets.Spreadsheets.Values.get('fileID', 'A1:Z1');
var studentHistory = Sheets.Spreadsheets.Values.get('fileID', 'A2:Z200');
var templateId = 'fileID';
var documentId;
var dstFolder = DriveApp.getFolderById('folderID');
var length = studentHistory.length;
Logger.log(studentHistory);
Logger.log(length);
//Loop through rows in sheet
for (var i = 0; i < length; i++){
//Get values from sheet row
var date = studentHistory.values[i][0];
var studentName = studentHistory.values[i][1];
var dob = studentHistory.values[i][2];
var pcDoctor = studentHistory.values[i][3];
var address = studentHistory.values[i][4];
var fgName = studentHistory.values[i][5];
var mgName = studentHistory.values[i][6];
var phoneMom = studentHistory.values[i][7];
var phoneDad = studentHistory.values[i][8];
var empMom = studentHistory.values[i][9];
var empDad = studentHistory.values[i][10];
var livesWith = studentHistory.values[i][11];
var childrenInHome = studentHistory.values[i][12];
var childrenNotInHome = studentHistory.values[i][13];
var othersInHome = studentHistory.values[i][14];
var illnesses = studentHistory.values[i][15];
var illnessDetails = studentHistory.values[i][16];
var hospitalizations = studentHistory.values[i][17];
var hospDetails = studentHistory.values[i][18];
var trauma = studentHistory.values[i][19];
var traumaDetails = studentHistory.values[i][20];
var injuries = studentHistory.values[i][21];
var injuryDetails = studentHistory.values[i][22];
var medications = studentHistory.values[i][23];
var additionalComments = studentHistory.values[i][24];
var otherSchools = studentHistory.values[i][25];
//Make a copy of the template file
documentId = DriveApp.getFileById(templateId).makeCopy(dstFolder).getId();
//Change name of newly created document
DriveApp.getFileById(documentId).setName('SocialHistory_' + studentName + '_' + date);
var body = DocumentApp.openById(documentId).getBody();
//Insert values
body.replaceText('<<date>>', date);
body.replaceText('<<studentName>>', studentName);
body.replaceText('<<dob>>', dob);
body.replaceText('<<pcDoctor>>', pcDoctor);
body.replaceText('<<address>>', address);
body.replaceText('<<fgName>>', fgName);
body.replaceText('<<mgName>>', mgName);
body.replaceText('<<phoneMom>>', phoneMom);
body.replaceText('<<phoneDad>>', phoneDad);
body.replaceText('<<empMom>>', empMom);
body.replaceText('<<empDad>>', empDad);
body.replaceText('<<livesWithe>>', livesWith);
body.replaceText('<<childrenInHome>>', childrenInHome);
body.replaceText('<<childrenNotInHome>>', childrenNotInHome);
body.replaceText('<<othersInHome>>', othersInHome);
body.replaceText('<<illnesses>>', illnesses);
body.replaceText('<<illnessDetails>>', illnessDetails);
body.replaceText('<<hospitalizations>>', hospitalizations);
body.replaceText('<<hospDetails>>', hospDetails);
body.replaceText('<<trauma>>', trauma);
body.replaceText('<<traumaDetails>>', traumaDetails);
body.replaceText('<<injuries>>', injuries);
body.replaceText('<<injuryDetails>>', injuryDetails);
body.replaceText('<<medications>>', medications);
body.replaceText('<<additionalComments>>', additionalComments);
body.replaceText('<<otherSchools>>', otherSchools);
}
}
studentHistory.values is the array.
Therefore, try this instead to get the length:
var length = studentHistory.values.length;
Solution
I see you are using Advanced Google Services to call the Sheets API. This Apps Script class allows you to call the Google APIs directly from your script handling automatically the authorization process.
However it doesn't work as the built in Classes that are available for example inside the SpreadsheetApp wrapper.
Your request will return an HTTP-like response following these specifications:
{
"range": string,
"majorDimension": enum (Dimension),
"values": [
array
]
}
You will need to parse these responses in order to achieve the desired result.
Proposed modification
function createDocument()
{
//var headers = Sheets.Spreadsheets.Values.get('fileID', 'A1:Z1');
var studentHistory = Sheets.Spreadsheets.Values.get('fileID', 'A2:Z200');
var templateId = 'fileID';
var documentId;
var dstFolder = DriveApp.getFolderById('folderID');
var length = studentHistory.values.length;
...
Reference
Google Sheets API
Advanced Google Services
I want to convert a dynamically created document to a PDF. It works when there is not a lot of data in the doc. However if my table's lenght goes above a certain value it does not want to work. Does anyone know what I can do?
function myFunction() {
var tempFolder = DriveApp.getFolderById("FOLDER_ID");
var tempDoc = DriveApp.getFileById("tEMP_DOC_ID");
var tempFile = tempDoc.makeCopy(tempFolder);
var table = tableDat2.map(function(r) {
return [r[0].toString(), r[1], r[4], Number(r[7]).toFixed(2), Number(r[9]).toFixed(2), Number([10]).toFixed(2), Number(r[11]).toFixed(2)]
});
table.unshift(headingData[0]);
var DocUse = DocumentApp.openById("DOCUMENT_O_USE ID");
var body = DocUse.getBody();
var style = {};
style[DocumentApp.Attribute.FONT_SIZE] = 6;
body.replaceText("{shopName}", shopName);
body.replaceText("{Street}", street);
body.replaceText("{Suburb}", suburb);
body.replaceText("{City}", city);
body.replaceText("{Country}", country);
body.replaceText("{telephoneNumber}", telephoneNo);
body.replaceText("{email}", email);
body.replaceText("{orderDate}", orderDate);
body.replaceText("{sdd}", sDD);
body.replaceText("{rd}", rD);
body.replaceText("{parameter}", param);
body.replaceText("{order}", orderNo);
body.replaceText("{totalValue}", totalVal);
body.replaceText("{totalWeight}", totalWeight);
body.replaceText("{totalPallets}", totalPal);
body.appendTable([headingData[0]]);
var tab = body.appendTable(table);
tab.setAttributes(style);
DocUse.saveAndClose();
var pdfFolder = DriveApp.getFolderById("FOLDER'S ID");
var PDF1 = DocUse.getAs(MimeType.PDF);
var PDF = pdfFolder.createFile(PDF1).setName("Quotation of: " + shopName + "Order no: " + orderNo);
return PDF;
}
I've been searching for the answer to this question but have so far been unable to piece together the answer. Please explain any answer you have in really simple terms as I'm fairly new to GAS and RegEx. I've got most of the syntax down but the execution of it in GAS is giving me a hard time.
Basically, I want to write a script that, when the spreadsheet is edited, checks which rows have yet to be merged. Then, on those rows, creates a copy of a template Google Doc and names the document based on the spreadsheet data. From there (this is the hard part), I need it to replace merge tags in the template with the data from the spreadsheet.
The tags in the templates I'll be using look like this: <<mergeTag>>
My idea was to match the whole tag, and replace it with data from the spreadsheet that exists in the column with the same name as what's inside the "<<>>". Ex: <<FooBar>> would be replaced with the data from the column named FooBar. It would obviously be from the current row that needs the merging.
After that, all that's left is to send an email (a few more row-specific personalization) with that document attached (sometimes as a PDF) with the body of the message coming from an HTML file elsewhere in the project.
This is the whole thing I have so far (notice the placeholders here and there that I can personalize for each spreadsheet I use this for):
function onEdit() {
//SPREADSHEET GLOBAL VARIABLES
var ss = SpreadsheetApp.getActiveSpreadsheet();
//get only the merge sheet
var sheet = ss.getSheetByName("Merge Data");
//get all values for later reference
var range = sheet.getActiveRange();
var values = range.getValues();
var lastRow = range.getLastRow();
var lastColumn = range.getLastColumn();
//get merge checker ranges
var urlColumn = range.getLastColumn();
var checkColumn = (urlColumn - 1);
var checkRow = range.getLastRow();
var checkRange = sheet.getRange(2, checkColumn, checkRow);
var check = checkRange.getBackgrounds();
//get template determination range (unique to each project)
var tempConditionRange = sheet.getRange(row, column);
var tempConditionCheck = tempConditionRange.getValues();
//set color variables for status cell
var red = "#FF0000";
var yellow = "#FFCC00";
var green = "#33CC33";
//////////////////////////////////////////////////////////
//DOC GLOBAL VARIABLES
var docTemplate1 = DriveApp.getFileById(id);
var docTemplate2 = DriveApp.getFileById(id);
var docTemplate3 = DriveApp.getFileById(id);
var folderDestination = DriveApp.getFolderById(id);
//////////////////////////////////////////////////////////
//EMAIL GLOBAL VARIABLES
var emailTag = ss.getRangeByName("Merge Data!EmailTag");
var personalizers = "";
var subject = "" + personalizers;
var emailBody = HtmlService.createHtmlOutputFromFile("Email Template");
//////////////////////////////////////////////////////////
// MERGE CODE
for (i = 0; i < check.length; i++) {
//for rows with data, check if they have already been merged
if (check[i] == green) {
continue;
} else {
var statusCell = sheet.getRange((i+2), checkColumn, 1, 1);
var urlCell = sheet.getRange((i+2), urlColumn, 1, 1);
var dataRow = sheet.getRange((i+2), 1, lastRow, (lastColumn - 2))
statusCell.setBackground(red);
//for rows with data, but not yet merged, perform the merge code
//////////////////////////////////////////////////////////
//DOC CREATION
//Determine which template to use
if (tempConditionCheck[i] == "") {
var docToUse = docTemplate1;
}
if (tempConditionCheck[i] == "") {
var docToUse = docTemplate2;
}
if (tempConditionCheck[i] == "") {
var docToUse = docTemplate3;
}
//Create a copy of the template
//Rename the document using data from specific columns, at specific rows
//Move the doc to the correct folder
var docName = "";
var docCopy = docToUse.makeCopy(docName, folderDestination);
var docId = docCopy.getId();
var docURL = docCopy.getUrl();
var docToSend = DriveApp.getFileById(docId);
var docBody = DocumentApp.openById(docId).getBody();
Here's where I need the help
//Locate the Merge Tags
//Match Merge Tags to the column headers of the same name
//Replace the Merge Tags with the data from the matched column, from the correct row
function tagReplace() {
var tagMatch = "/(<{2}(\w+)>{2})/g";
}
statusCell.setBackground(yellow);
urlCell.setValue(docURL);
The rest is just finishing up the process
//////////////////////////////////////////////////////////
//EMAIL CREATION
//Create an email using an HTML template
//Use Merge Tags to personalize email
//Attach the doc we created to the email
//Send email to recipients based on data in the sheet
MailApp.sendEmail(emailTag, subject, emailBody, {
name: "Person McPerson",
attachments: [docToSend], //[docToSend.getAs(MIME.PDF)],
html: emailBody,
});
//////////////////////////////////////////////////////////
//CHECK ROW UPDATE
statusCell.setBackground(green);
}
}
}
My sheets all have a frozen first row that acts as the header row. All my columns will be consistently named the exact same thing as the tags (minus the <<>>).
How do I match the tags to the data?
EDIT
```````````````````
The solution did not work as described when I inserted it into my code as follows:
function formMerge() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Merge Data");
var urlColumn = sheet.getMaxColumns();
var checkColumn = urlColumn - 1;
var lastRow = ss.getSheetByName("Form Responses").getLastRow();
var values = sheet.getDataRange().getValues();
var headers = values[0];
var urlRange = sheet.getRange(2, urlColumn, lastRow);
var checkRange = sheet.getRange(2, checkColumn, lastRow);
var check = checkRange.getBackgrounds();
var red = "#ff0404";
var yellow = "#ffec0a";
var green = "#3bec3b";
var docTemplate = DriveApp.getFileById(id);
var folderDestination = DriveApp.getFolderById(id);
// MERGE CODE
for (i = 0; i < check.length; i++) {
if (check[i] == green) {
continue;
} else {
var statusCell = sheet.getRange((i+2), checkColumn, 1, 1);
var urlCell = sheet.getRange((i+2), urlColumn, 1, 1);
var dataRow = sheet.getRange((i+2), 1, 1, (urlColumn - 2)).getValues();
var clientNameRange = sheet.getRange((i+2), 3);
var clientName = clientNameRange.getValue();
var dateRange = sheet.getRange((i+2), 2);
var datePreFormat = dateRange.getValue();
var timeZone = CalendarApp.getTimeZone();
var date = Utilities.formatDate(new Date(datePreFormat), timeZone, "MM/dd/yyyy");
statusCell.setBackground(red);
//EMAIL VARIABLES
var personalizers = clientName;
var subject = "Post Intake Report for " + personalizers;
var emailBody = "Please see the attached Google Doc for the Post Intake Report for " + clientName + ". The intake was performed on " + date + ".";
var emailTagRange = sheet.getRange((i+2), 24);
var emailTagValue = emailTagRange.getValue();
var emailTag = emailTagValue.split(", ");
//DOC CREATION
var docToUse = docTemplate;
var docName = "Post Intake Report - " + clientName + " [" + date + "]";
var docCopy = docToUse.makeCopy(docName, folderDestination);
var docId = docCopy.getId();
var docURL = docCopy.getUrl();
var docBody = DocumentApp.openById(docId).getBody().editAsText();
for (var j=0; j<headers.length; j++) {
var re = new RegExp("(<<"+headers[j]+">>)","g");
docBody.replaceText(re, dataRow[j]);
}
statusCell.setBackground(yellow);
urlCell.setValue(docURL);
//EMAIL CREATION
MailApp.sendEmail(emailTag, subject, emailBody, {
name: "Christopher Anderson",
attachments: [docCopy],
html: emailBody
});
statusCell.setBackground(green);
}
}
}
Build the RegExp for each tag on the fly, using the header values from your spreadsheet.
Use Body.replaceText() to perform the replacements.
var values = sheet.getDataRange().getValues();
var headers = values[0];
...
// Loop over all columns. Use header names to search for tags.
for (var col=0; col<headers.length; col++) {
// Build RegExp using column header
var re = new RegExp("(<{2}"+headers[col]+">{2})","g");
// Replace tags with data from this column in dataRow
body.replaceText(re, dataRow[col]);
}
This snippet will operate on a single row; the first couple of declarations should appear outside of your row loop. The column looping is then done after you've created and opened the new document, and obtained the body object.
It loops over all the columns in the spreadsheet, using the header names to find the tags you've defined, and replaces them with the corresponding cell contents for the current row.
I am reading JSON from a Google Spreadsheet and need help getting to the text within entry.content.$t. The text is a column named "description" in the spreadsheet. The feed for the spreadsheet is (removed)
So far, my script is
function listChapters(root) {
var feed = root.feed;
var entries = feed.entry || [];
var html = ['<ul>'];
for (var i = 0; i < entries.length; ++i) {
var chlist = entries[i];
var title = (chlist.title.type == 'html') ? chlist.title.$t : escape(chlist.title.$t);
var chapters = chlist.content.$t;
html.push('<li>', chapters, '</li>');
}
html.push('</ul>');
document.getElementById("chapterlist").innerHTML = html.join("");
}
The question is - How do I read "description" from $t to place in the var chapters?
The text within chlist.content.$t is almost, but not quite, properly formatted JSON. Since it's not properly formatted, you cannot use JSON.parse() to create an object that you could then get a description property from.
Here's a brute-force approach that will extract the description, used in place of the original html.push('<li>', chapters, '</li>');:
// Get the text between 'description: ' and 'Chapter website:'
var descStart = chapters.indexOf('description:')+13; //+length of 'description: '
var descEnd = chapters.indexOf('Chapter website:');
var description = chapters.substring(descStart,descEnd);
html.push('<li>', description, '</li>');
Tested with this, checking results in debugger:
function test() {
var url = '---URL---';
var result = UrlFetchApp.fetch(url);
var text = result.getContentText();
var bodytext = Xml.parse(text,true).html.body.getText();
var root = JSON.parse(bodytext);
listChapters(root);
}