I'm need some assistance in my problem.
I'm currently working on a script that works like this :
Send form
Lookup the value in table
Get the row number to use in another function
I have searched for the solution but mostly use logger to display value, I need the value as local variable to be used in other function.
Here is my current code up until the point I try to get row number :
function autoFillGoogleDocFromForm(e) {
//e.values is an array of form values
var Timestamp = e.values[0];
var Nama = e.values[1];
var Prinsipal = e.values[2];
var Email = e.values[3];
var Site = e.values[4];
var Mobil = e.values[5];
var Jumlah = e.values[6];
var ETD = e.values[7];
var ETA = e.values[8];
var Keterangan = e.values[9];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Master Email Site');
var data = sheet.getDataRange().getValues();
var RowCabang = Site
for(var i = 0; i<data.length;i++){
if(data[i][0] == Site){ //[0] because column A
return i+1;
}
}
var EmailCol = 2;
var EmailDest = sheet.getRange(RowCabang, EmailCol).getValue();
With this script, the trigger is completed but it doesnt capture the row number as var to be used.
Thank you for your assistance.
Try this pattern:
let RowCabang;
data.some((row, index) => {
if (row[0] === Site) {
RowCabang = index + 1;
return true;
}
});
Related
I'm automating my google sheets to send out emails automatically and I can't figure out how to compare a variable array to a column in my google sheets. I keep getting all values returned rather than just the ones in my array when I put it in an 'IF' statement.
I want my code to only show data that is in my gEnglish variable but instead shows me all data. I was also wondering how I'd be able to send emails based on regions to users.
function sendEmails() {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Main").activate();
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = ss.getLastRow();
var decisionOne = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Templates").getRange(1,1).getValue();
var decisionTWO = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Templates").getRange(2,1).getValue();
var decisionThree = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Templates").getRange(3,1).getValue();
var decisionFour = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Templates").getRange(5,1).getValue();
var decisionFive = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Templates").getRange(4,1).getValue();
var gEnglish = ["IT","US","GB","UK"];
var gSpanish = ["SP"];
var user1 = ["JP","SK","IND","RU"];
var user2 = [gEnglish,"UK"];
var user3 = [gSpanish, "BR", "PT"];
var user4 = ["FR", "DE","IT"];
for (var i = 2;i<=lr;i++){
var type = ss.getRange(i,6).getValue();
var region = ss.getRange(i, 5).getValue();
var decision = ss.getRange(i,15).getValue();
//I used to have if(region == gEnglish)
if(gEnglish.includes(region[i]) ){
var channel = ss.getRange(i,3).getValue();
var decision = ss.getRange(i,15).getValue();
var url = ss.getRange(i, 9).getValue();
var name = ss.getRange(i,11).getValue();
var messageBody = {};
var subjectLine = "blahblahblah";
}
}
}
If my array only has one value inside it works fine but as soon as I put more I just get all values returned.
What am I doing wrong?
Putting a column into a flat array.
function col2array() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Sheet1');
const vA=sh.getRange(1,1,sh.getLastRow(),1).getValues().flat();
}
In Google Apps Script a column looks like:
[[Row1],[Row2],[Row3],[Row4]....]
function lookingforarrayvaluesinacolumn() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Sheet1');
const vA=sh.getRange(1,1,sh.getLastRow(),1).getValues();
const coolpeople = ["p1","p2"];
vA.forEach(function(r,i){
if(coolpeople.indexOf(r[0])!=-1) {
//the r[0] is a cool person
}
});
}
I have one sheet for a group of people. I'm trying to make a script so that whenever they edit the sheet, the time that they last edited will show up in a sheet in another document.
A sample row from the group sheet looks like this:
col1|...|col10|person name|...|col17
and the sheet that the time should be going to looks like this:
person name|col2|...|col10|date last edited.
this is the code that I've been trying and it is not working so far:
function onEdit(e) {
var row = e.range.getRow();
var col = e.range.getColumn();
var time = new Date().toLocaleString("en-US", {timeZone: "America/Toronto"})
var ID = "sheet ID"; //The ID for the second sheet goes here
var sheet = SpreadsheetApp.OpenById(ID);
var target = sheet.getSheetByName("Sheet2");
var lastColumn = target.getLastColumn();
var lastRow = target.getLastRow();
var range = target.getRange(1,1,lastRow, lastColumn);
var data = range.getValues();
var userEmail = e.user.getEmail();
var array = userEmail.split(".");
var firstName = array[0];
var secondSheet = e.source.getActiveSheet();
var lastRowSecond = secondSheet.getLastRow();
var lastColumnSecond = secondSheet.getLastColumn();
var secondRange = secondSheet.getRange(1,1,lastRowSecond, lastColumnSecond);
var secondData = secondRange.getValues();
var nameRow = secondData[row-1];
var nameColumn = nameRow[10];
var secondPersonarray = nameColumn.split(" ");
var secondPersonFirstName = secondPersonarray[0];
for (var i=1; i<lastRow; i++) {
var sheetRow = data[i];
var name = sheetRow[0].split(" ");
var firstNameSheet = name[0];
if ((firstName == firstNameSheet) && (firstName == secondPersonFirstName)) {
target.getRange(sheetRow, 10).setValue(time);
}
}
}
I've done something similar, only with one document, so I know the problem isn't with the time.
I'm trying to create a script that will create new documents from a template-document. Replace placeholders in the documents with data from the sheet based on a keyword search in a specific column. And then change the row's value in the specific column so that the row will not process when the script runs again.
I think I've got it right with the first keyword search, and the loop through the rows. But the last part to get the data to 'merge' to the placeholders I can't figure out how to. I just get the value "object Object" and other values in the document.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var lastColumn = s.getLastColumn();
function createDocFromSheet() {
var headers = getUpsertHeaders(s);//function is defined outside of this function
var statusColNum = headers.indexOf('Status')+1;
var row = getRowsData(s); //The function is defined outside this function.
for (var i=0; i<row.length; i++) {
var jobStatus = '';
if (row[i]['Status'] === '') {
//New: write the status to the correct row and column - this will be moved to the end when I get the rest right
var jobStatus = "Created";
s.getRange(i+2, statusColNum).setValue(jobStatus);
//Find the template and make a copy. Activate the body of the new file.
var templateFile = DriveApp.getFileById('1lkfmqsJMjjPujHqDqKtcDmL-5GMIxpOWTyCOaK29d2A');
var copyFile = templateFile.makeCopy()
var copyId = copyFile.getId()
var copyDoc = DocumentApp.openById(copyId)
var copyBody = copyDoc.getActiveSection()
//Find the rows Values as an object.
var rows = s.getRange(i+2,1,1,lastColumn)
var rowsValues = rows.getValues();
Logger.log(rowsValues)
//Until here I think it's okay but the last part?
//HOW TO replace the text???
for (var columnIndex = 0; columnIndex < lastColumn; columnIndex++) {
var headerValue = headerRow[columnIndex]
var rowValues = s.getActiveRange(i,columnIndex).getValues()
var activeCell = rowsValues[columnIndex]
//var activeCell = formatCell(activeCell);
Logger.log(columnIndex);
copyBody.replaceText('<<' + headerValue + '>>', activeCell)
}
Template doc : Link
Template sheet: Link
You can use the following GAS code to accomplish your goals:
var DESTINATION_FOLDER_ID = 'YOUR_DESTINATION_FOLDER_ID';
var TEMPLATE_FILE_ID = 'YOUR_TEMPLATE_FILE_ID';
function fillTemplates() {
var sheet = SpreadsheetApp.getActiveSheet();
var templateFile = DriveApp.getFileById(TEMPLATE_FILE_ID);
var values = sheet.getDataRange().getDisplayValues();
var destinationFolder = DriveApp.getFolderById(DESTINATION_FOLDER_ID);
for (var i=1; i<values.length; i++) {
var rowElements = values[i].length;
var fileStatus = values[i][rowElements-1];
if (fileStatus == 'Created') continue;
var fileName = values[i][0];
var newFile = templateFile.makeCopy(fileName, destinationFolder);
var fileToEdit = DocumentApp.openById(newFile.getId());
for (var j=1; j<rowElements-1; j++) {
var header = values[0][j];
var docBody = fileToEdit.getBody();
var patternToFind = Utilities.formatString('<<%s>>', header);
docBody.replaceText(patternToFind, values[i][j]);
}
sheet.getRange(i+1, rowElements).setValue('Created');
}
}
You only have to replace the 1st and 2nd lines as appropriate. Please do consider as well that the code will assume that the first column is the file name, and the last one the status. You can insert as many columns as you wish in between.
After some coding I ended up with this code to process everything automatic.
Again thanks to #carlesgg97.
The only thing I simply can't figure out now is how to generate the emailbody from the template with dynamic placeholders like in the document. How to generate the var patternToFind - but for the emailbody?
I've tried a for(var.... like in the document but the output doesn't replace the placeholders.
var DESTINATION_FOLDER_ID = '1inwFQPmUu1ekGGSB5OnWLc_8Ac80igK0';
var TEMPLATE_FILE_ID = '1lkfmqsJMjjPujHqDqKtcDmL-5GMIxpOWTyCOaK29d2A';
function fillTemplates() {
//Sheet variables
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data');
var values = sheet.getDataRange().getDisplayValues();
//Header variables
var headers = sheet.getDataRange().getValues().shift();
var idIndex = headers.indexOf('ID');
var nameIndex = headers.indexOf('Name');
var emailIndex = headers.indexOf('Email');
var subjectIndex = headers.indexOf('Subject');
var statusIndex = headers.indexOf('Status');
var fileNameIndex = headers.indexOf('File Name');
var filerIndex = headers.indexOf('Filer');
var birthIndex = headers.indexOf('Date of birth');
//Logger.log(statusIndex)
//Document Templates ID
var templateFile = DriveApp.getFileById(TEMPLATE_FILE_ID);
//Destination
var destinationFolder = DriveApp.getFolderById(DESTINATION_FOLDER_ID);
var templateTextHtml = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Email').getRange('D11').getValue();
//Run through the variables
for (var i=1; i<values.length; i++) {
//If first column is empty then stop
var index0 = values[i][0];
if(index0 == "") continue;
var rowElements = values[i].length;
var fileStatus = values[i][statusIndex];
//If the row already processed then stop
if (fileStatus == "Created") continue;
//If the row is not processed continue
//Define the new filename by the relevant Column
var fileName = values[i][fileNameIndex];
var newFile = templateFile.makeCopy(fileName, destinationFolder);
var fileToEdit = DocumentApp.openById(newFile.getId());
//Replace placeholders in the new document
for (var j=1; j<rowElements-1; j++) {
var header = values[0][j];
var docBody = fileToEdit.getBody();
var patternToFind = Utilities.formatString('{{%s}}', header);
docBody.replaceText(patternToFind, values[i][j]);
}
//Create the PDF file
fileToEdit.saveAndClose();
var newPdf = DriveApp.createFile(fileToEdit.getAs('application/pdf'));
DriveApp.getFolderById(DESTINATION_FOLDER_ID).addFile(newPdf);
DriveApp.getRootFolder().removeFile(newPdf);
newFile.setTrashed(true);
var newPdfUrl = newPdf.getUrl();
//Create the emailbody
var textBodyHtml = templateTextHtml.replace("{{Name}}",values[i][nameIndex]).replace("{{Date of birth}}",values[i][birthIndex]);
var textBodyPlain = textBodyHtml.replace(/\<br>/mg,"");
//Will send email to email Column
var email = values[i][emailIndex];
var emailSubject = values[i][idIndex]+" - "+values[i][fileNameIndex]+" - "+values[i][nameIndex];
MailApp.sendEmail(email,emailSubject,textBodyPlain,
{
htmlBody: textBodyHtml+
"<p>Automatic generated email</p>",
attachments: [newPdf],
});
sheet.getRange(i+1, filerIndex+1).setValue(newPdfUrl);
sheet.getRange(i+1, statusIndex+1).setValue('Created');
}//Close for (var i=1...
}
How to search a column on a sheet for a value, and if the value is there continue code? I am trying to make an update system to check to see if their email is on a sheet. If their email is on a sheet then it will check if their system version is up to date. If the system is not to up to date it will then copy their data, delete their current sheet, create a copy from an example then put in their data. If the user does not have the system it will create one for them. It seems to continuously skip Checking their email.
My code uses URLs and IDs but I have taken them out for obvious reasons. Below is an example of the beginning of my code.
function readlog()
var user = Session.getEffectiveUser().getUsername();
var email = Session.getEffectiveUser().getEmail();
var ss = SpreadsheetApp.openByUrl(URL_);
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet = sheet.getSheetByName('8th grade')
var active = sheet.getRange('8th grade!b3:b').getValues()
if (email == active) {
//do something
}
Here is a full version of my code:
function readlog(){
var user = Session.getEffectiveUser().getUsername();
var email = Session.getEffectiveUser().getEmail();
var timezone= "CST";
var date = Utilities.formatDate(new Date(),timezone, "E MMM dd,yyyy HH:mm:ss");
var ss = SpreadsheetApp.openByUrl(URL_);
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet = sheet.getSheetByName('8th grade')
var active = sheet.getRange('8th grade!b3:b').getValues()
if (email == active) {
var container = DriveApp.getFoldersByName('Reading Log')
var fid = DriveApp.getFoldersByName('Reading Log').getId()
var version = sheet.getRange('8th grade!a1')
var update = container.getDescription();
if (update == version) {
var ui = SpreadsheetApp.getUi();
var response = ui.alert('You already have a reading log, and you have the most recent update!', ui.ButtonSet.OK);
} else {
var contents = container.getFiles();
var files = DriveApp.getFolderById(fid).searchFiles(
'title contains "Reading log"');
while (files.hasNext()) {
var file = files.next();
var logtoupdate = file.getUrl;
}
var ss = SpreadsheetApp.openByUrl(logtoupdate);
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var logrange = sheet.getRange('8th Grade!e5:o').getValues()
SpreadsheetApp.getActiveSpreadsheet().deleteActiveSheet();
var master = DriveApp.getFileById(URL_);
var read = master.makeCopy("Reading Log",container);
var target = read.getRange('8th Grade e5:o').setValues(logrange);
var range = sheet.getRange("A1:B2");
range.setValues([[50, 100]]);
var ss = SpreadsheetApp.openByUrl(URL_);
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet()
}
} else {
var ss = SpreadsheetApp.openByUrl(URL_);
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var targetFolder = DriveApp.createFolder("Reading Log");
var eighth = DriveApp.getFileById(URL_);
var share = eighth.makeCopy("(Name): 8th Grade Reading Log",targetFolder);
var master = DriveApp.getFileById(URL_);
var read = master.makeCopy("Reading Log",targetFolder);
var folder = sheet.getRange('8th grade!a1');
targetFolder.setDescription(folder);
var idsheet = read.getUrl();
var idshare = share.getUrl();
var idfolder = targetFolder.getUrl()
sheet.appendRow([user,email,date,idfolder,idsheet,idshare]);
var ui = SpreadsheetApp.getUi();
var response = ui.alert('Your Reading log is created. There is now a folder in your google drive called Reading log. Have Fun Reading!', ui.ButtonSet.OK);
}
}
Short answer
Instead of email == active use active.join('|').split('|').indexOf(email)
Explanation
getValues() return a two dimensional array.
join('|') convert this array into an string using | as separator.
split('|') convert the above string into an (one dimension) array.
indexOf(email) returns the index of the email value on the above array. If the email value is not found, -1 is returned.
On a comparison -1 is parsed as false.
function getColIndexByName(colName) {
var sheet = SpreadsheetApp.getActiveSheet();
var numColumns = sheet.getLastColumn();
var row = sheet.getRange(1, 1, 1, numColumns).getValues();
for (i in row[0]) {
var name = row[0][i];
if (name == colName) {
return parseInt(i) + 1;
}
}
return -1;
}
function sendtoContacts () {
var source = SpreadsheetApp.getActiveSpreadsheet();
var ss = source.getActiveSheet();
var row = ss.getActiveRange().getRowIndex();
var group = ContactsApp.getContactGroup('From Googlesheet');
var givenName = ss.getRange(row, getColIndexByName("First")).getValue();
var familyName = ss.getRange(row, getColIndexByName("Last")).getValue();
var email = ss.getRange(row, getColIndexByName("Work Gmail")).getValue();
var Homeemail = ss.getRange(row, getColIndexByName("Personal Email")).getValue();
var company = ss.getRange(row, getColIndexByName("Company")).getValue();
var title = ss.getRange(row, getColIndexByName("Title")).getValue();
var phone = ss.getRange(row, getColIndexByName("Phone")).getValue();
var mobile = ss.getRange(row, getColIndexByName("Mobile")).getValue();
var newContact = ContactsApp.createContact(givenName, familyName, email);
var contactid = newContact.getId();
var addy = ss.getRange(row, getColIndexByName("Address")).getValue();
var city = ss.getRange(row, getColIndexByName("City")).getValue();
var prov = ss.getRange(row, getColIndexByName("Prov")).getValue();
var pc = ss.getRange(row, getColIndexByName("Postal Code")).getValue();
var address = addy + ", " + city + ", " + prov + ", " + pc
var AltContact = ss.getRange(row, getColIndexByName("Alt Contact Name")).getValue();
var AltRelation = ss.getRange(row, getColIndexByName("Alt ContactRelation")).getValue();
var AltPhone = ss.getRange(row, getColIndexByName("Alt Contact Phone")).getValue();
var AltWork = ss.getRange(row, getColIndexByName("Alt Contact Wk No")).getValue();
var AltMobile = ss.getRange(row, getColIndexByName("Alt Contact Mobile")).getValue();
newContact.addToGroup(group);
newContact.addAddress("Home", address);
newContact.addCompany(company, title);
newContact.addEmail("Home", Homeemail);
newContact.addCustomField("Emergency Contact", AltContact);
newContact.addCustomField("Emergency Contact Relation", AltRelation);
newContact.addCustomField("Emergency Contact Work", AltWork);
newContact.addCustomField("Emergency Contact Mobile", AltMobile);
for ( var i = 0; i < phone.length ; i++){
if (phone[i][3] != ''){ newContact.addPhone("HOME", phone); return}};
for ( var i = 0; i < mobile.length ; i++){
if (mobile[i][44] != ''){ newContact.addPhone("Mobile", mobile); return}};
}
function MakeAllContacts() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var ss = source.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 100; // Number of rows to process
for (row = 2; row < 6; row++)
{
sendtoContacts();
}
return
}
Here I am duplicating the entries with MakeAllContacts() but I want to make the RowIndex change to every row in the sheet so it add all the contacts in the sheet. Here is at Video I made explaining it Video and here is a link to my actual sheet Google Sheet. I have a fair bit of code I would like to start sharing if I could just get my head are around looping instead of the one row to be All the rows in the sheet. Thanks for any help is appreciated.
Your sendtoContacts () function is using ss.getActiveRange().getRowIndex(); to determine which row to use but nowhere in your script you set any row to active so you keep using the same data all the way through the main loop in MakeAllContacts().
There are 2 possible solutions :
use activate() in the MakeAllContacts() function loop so that the active row changes for each iteration (ss.getRange(row,1).activate())
use a rowIndex parameter in the sendtoContacts () function like below :
function MakeAllContacts() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var ss = source.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 100; // Number of rows to process
for (row = 2; row < numRows; row++){
sendtoContacts(row);
}
}
and then change the function sendtoContacts () function like this:
function sendtoContacts (row) { // row as parameter
var source = SpreadsheetApp.getActiveSpreadsheet();
var ss = source.getActiveSheet();
...
That said, this approach is not very efficient since each data is read in the spreadsheet using a single getRange/getValue which is particularly slow... please read the best practice to get inspiration on how to handle your data more efficiently using a single getValues() and iterate the array content instead.