I'm working on a spreadsheet that uses multiple =IMPORTXML functions to import changing text and price values from a webpage. At this moment I have the following columns in my Google Sheet:
A: 'URL info'
B: 'URL'
F-N: 'Price' (in every column a different price value)
What I have
Via a script, found on this page (thank you Umesh Agarwal) I will receive an email notification once a change has been made within the spreadsheet. Once I make a change in a cell within the range of F2:N200 I will receive an email with the cell that have been changed. The problem is that I have the script to sent me an email with the changed cell once the cell with a value of the =importxml function is changing.
At this moment, when a cell is changing due to the =importxml function the script is sending me an email that cell A1 has changed... it is not sending me the right cell that has been changed which makes it difficult to see what changed. How can I solve this problem?
function sendEmailonEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cellValue = ss.getActiveSheet().getActiveRange().getA1Notation();
var getColumn = ss.getActiveSheet().getActiveRange().getColumn();
var sheetname = ss.getActiveSheet().getName();
var user = Session.getActiveUser().getEmail();
var Toemail = 'myemailid_1234#gmail.com';
var subject = 'New Entry in ' + data + '.' + ss.getName();
var body = 'Your file has a new entry in - ' + sheetname + ' Updated by - ' + user + data
' check file- ' + ss.getUrl();
if(data.indexOf('F2:N200')!=-1.23456789) {
MailApp.sendEmail(Toemail,subject, body);
}
};
I'm afraid this is not possible with triggers the way you have it set up.
For the trigger to fire when a formula is pulling data from an external source "On change" is the only trigger that will pick up the change. Unfortunately, it won't return which cell or value has changed, it will only return which sheet has changed.
The other alternative trigger you might run into is "on Edit", however, this trigger will not fire when the sheet is updated by formulas pulling data from an external source ¯\_(ツ)_/¯
Avenue for possible workaround:
You might be able to work around this with a Time-driven trigger AKA clock trigger. Writing a script that fires every so often to check for changes in the worksheet, and to send an e-mail if it does. You might copy all the data to another sheet and then compare the values, or use the Properties Service, to persist data within the script.
I'm looking for a script that would send an automatic email to a seller (column J) when a change is made to one of his customers. The change is made through a google form. So the form is linked to a spreadsheet and I added a tab where I did a vlookup in column J of the customer number. It works when I manually typed the email adress but it doesn't when it's the vlookup formula... here's the code I have for now.
Thanks in advance.
function twchange3(e) {
var range = e.range;
if (e.range.getColumn()== 10) {
var sheet = SpreadsheetApp.getActiveSheet();
var row = SpreadsheetApp.getActiveRange().getRow();
var value = sheet.getRange(row, 1, 1, 10).getValues();
var email = value[0][9];
var router = value[0][1];
var noclient = value[0][3];
var nomclient = value[0][4];
var twactuel = value[0][5];
var twdemande = value[0][6];
var raison = value[0][7];
MailApp.sendEmail(value[0][9], "Demande de changement de Time-Window",
"Bonjour voici une demande de changement de Time-Window pour votre client " + nomclient + "\n\n" +
"Numéro de client: " + noclient + "\n\n" +
"Time-Window Actuel: " + twactuel + "\n\n" +
"Time-Window demandé: " + twdemande + "\n\n" +
"Raison: " + raison + "\n\n" +
"Auteur de la demande: " + router + "\n\n");
}
}
Let me rephrase what you've said.
A client submits a Google Form, which sends a result to Tab A of a Google Sheet.
Then there is Tab B that is using a VLOOKUP function to check the latest result in the Google Sheet.
When you change a cell with the email manually in Tab A, the script works.
When you use the Google Form to submit a response, the script does not run.
There are a few problems here.
When you manually change the Sheet, you activate the onEdit trigger.
When you update the Sheet via the Google Form, it is unlikely that onEdit gets triggered because onEdit is normally a user domain. It is likely that onChange is supposed to be triggered instead, and you might not even have it set up.
Then, even if you set up onChange and it fires, I'd say it is unlikely that the change will be occurring in the VLOOKUP cell of Tab B because the latter is just a filter, and the actual change is likely to be happening in Tab A. I am saying likely because I decided not to test it since your description of the issue was not very clear.
So you do not actually need VLOOKUP here, just read the changing cell directly with the script.
Even a better solution might be reading the response directly from the Google Form with its own script and triggers.
My company has created a Google Form set up to make one of our processes a lot easier. The Google Form is based off of the Master Spreadsheet that contains all of the data inputted from the Form. This spreadsheet then filters out the the form submission and sends the data to each department’s spreadsheet, which as previously stated before, gets all of the information from the "Master Spreadsheet."
We previously had it set up so when employees would go in and approve or deny these requests in their spreadsheet, we would receive an email notification if someone entered "Approved" or "Denied." Recently we changed it so if a certain person submitted a request for a customer, it would be automatically approved, but when we did this the email notification stopped working because no one is manually entering in "Approved" or "Denied" for these requests. It still works when it's manually typed in, but when the cell is automatically filled in, the sendNotification does not work.
Since no actual data is being input into the individual department sheets, we wanted to put the notification trigger on the "Master Sheet," but we are having a heck of a time getting the email notification to send. Basically we want it so if any cell in "Column F" contains a certain list of email addresses it will send an email to a third party notifying them to actually go ahead and make the changes.
Here is what we have so far. Keep in mind this is the code that worked originally. I've tried many different variations of things and have had no luck whatsoever, but I'm not the most educated coder:
function sendNotification() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Form Responses 3");
//Get Active cell
var mycell = ss.getActiveSelection();
var cellcol = mycell.getColumn();
var cellrow = mycell.getRow();
var cellValue = mycell.getValue();
var activeUser = Session.getActiveUser();
var recipients = "xxxx#xxxxxxxxxx.com";
var subject = "Update to "+ss.getName();
var body = activeUser + " has marked row " + cellrow + " \"" + cellValue + "\" in \"" + ss.getName() + "\". Visit " + ss.getUrl() + " to view the changes.";
if (cellcol == 2) {
if (cellValue.indexOf('test1#test.com') >= 0) {
var subject = "Lunch Is Served";
Logger.log('Sending approval notification of row ' + cellrow + ' to ' + recipients);
MailApp.sendEmail(recipients, subject, body);
}
}
}
Please keep in mind that we can't use lastRowNumber (at least I didn't think we could) because we already have over one thousand rows listed so the information will fill in to the array automatically.Lastly, our current trigger is set to "On Form Submission" because we want these emails to come in as the forms are submitted.
I have included a sample spreadsheet for you guys to look at. Please use test1#test.com as your email address when completing the form.
The Google Sheet can be found at the following site:
Test Sheet!
Thank you so much and I look forward to reading your responses!
You can't use the line:
var mycell = ss.getActiveSelection();
If that function is running from an "On Form Submit" trigger, there is no active selection. Although, there is a property available to the "On Form Submit" event object that gives the currently edited range. You must get the event object from the form submission. Then you have 3 options. 1) Just get the values 2) Get an object of questions and their values 3) Get the range of the range edited. First, you get the event object that is passed into the function. When the form is submitted, data is automatically made available to the function associated with the On Form Submit trigger. The letter e is typically used as the variable name to get the event object:
function sendNotification(e) {
But you can use any variable name:
function sendNotification(objOfData) {
Apps Script Documentation - Spreadsheet - On Form Submit
function sendNotification(e) {
var cellValue = e.values[4];//Get the value in column 5
I am relatively new to Google Apps Script and have been using a very simple script that I created about a year ago that is triggered when a user submits inputs via a Google Form. The script has been working perfectly until approximately this past May and I've been scrambling trying to figure out what happened when I haven't made any changes to my code. I have searched many different places and cannot seem to find what is wrong.
Basically, I have a form that users complete and then submit. Upon submission, the script takes the inputs from the most recent row and stores them in variables that would then be assembled into an email message confirmation that acknowledges each user's submitted input.
Here is my code:
function acknowledgement() {
var ActiveSheet = SpreadsheetApp.getActiveSheet();
var ActiveRow = ActiveSheet.getActiveRange().getRow();
var emailAddy = ActiveSheet.getRange("E"+ActiveRow).getValue();
var locvar = ActiveSheet.getRange("C"+ActiveRow).getValue();
var employeevar = ActiveSheet.getRange("B"+ActiveRow).getValue();
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Variables");
var contactvar = sh.getRange("A2").getValue();
var subject = sh.getRange("B2").getValue();
var contactvar2 = sh.getRange("C2").getValue();
var linebrk = "<br />";
var msg = "Dear " + employeevar + ","
+ linebrk + linebrk
+ "This confirms that you have completed your review of the latest security presentation."
+ linebrk + linebrk
+ "Your location number is " + locvar + "."
+ "Thank you very much for your participation."
+ linebrk + linebrk
+ contactvar;
var msghtml = '<p>'+msg+'</p>';
var advancedargs = {cc:contactvar2, htmlBody:msghtml};
MailApp.sendEmail(emailAddy, subject, msg, advancedargs);
}
What is currently happening is that my code is no longer grabbing the current row number (i.e. the active row that was just submitted by a user). Instead, it is simply grabbing the top row of the sheet (i.e. my row headings like 'Employee Name', 'Email Address', etc.) and assigning those row headings to the variables thus producing an error when trying to send the email confirmation. For instance my variable emailAddy would contain "Email Address" causing sendEmail to fail.
Any feedback would be appreciated!
Using getActiveRow in the context of a form submission is somewhat strange as one cannot consider that a user is actually active on the sheet... I don't know why you did choose that approach and I'm actually wondering how it happened to work for so long...
There are other possibilities to handle form submissions but the one that will need the fewest changes in your code is to simply use getLastRow() instead of getActiveRange().getRow()
There are a few risks to use that simple "strategy" as there might be concurrency issues when 2 or more people send a form simultaneously.
The other solution is to get all the field values directly from the event properties that comes on form submission as in that case each event is unique, no matter how it comes into the spreadsheet but your script will have to be rewritten more deeply.
I believe that Google Forms has well covered the case you mention, the trigger "onFormSubmit" the spreadsheet, receives an object as a parameter with all the information you need.
I agree with Serge that the script be rewritten deeply, but definitely, it will save many problems.
Go to the documentation, specifically in "Spreadsheet Form Submit Events" https://developers.google.com/apps-script/understanding_events.
You are looking for the code e.range.getRow().
So we have:
function onFormSubmit(e) {
const row = e.range.getRow()
}
You'll also need to setup a trigger to the onFormSubmit function.
Edit > Current project's triggers
Now (finally) some fun: everytime a form is submitted, you'll know the row it corresponds to. Have fun!
Note that the onFormSubmit function could have any name - the trigger will map to any named function and pass to it an "e" argument that contains range.getRow() among other information.
I would like to insert a timestamp (date and/or time) into Google Documents. The support documentation () says that there should be a keyboard shortcut, but it does not work in my environment (Win7 + IE9).
Can anyone provide me with a Google Apps script to achieve this?
This works well
In Google Docs : Tools -> Open Script Editor and save this script
function onOpen() {
var ui = DocumentApp.getUi();
// Or FormApp or SpreadsheetApp.
ui.createMenu('Custom Menu')
.addItem('Insert Date', 'insertDate')
.addToUi();
}
function insertDate() {
var cursor = DocumentApp.getActiveDocument().getCursor();
if (cursor) {
// Attempt to insert text at the cursor position. If insertion returns null,
// then the cursor's containing element doesn't allow text insertions.
var d = new Date();
var dd = d.getDate();
dd = pad(dd, 2)
var mm = d.getMonth() + 1; //Months are zero based
mm = pad(mm, 2)
var yyyy = d.getFullYear();
var date = dd + "-" + mm + "-" + yyyy;
var element = cursor.insertText(date);
if (element) {
element.setBold(true);
} else {
DocumentApp.getUi().alert('Cannot insert text at this cursor location.');
}
} else {
DocumentApp.getUi().alert('Cannot find a cursor in the document.');
}
}
function pad (str, max) {
str = str.toString();
return str.length < max ? pad("0" + str, max) : str;
}
Reload the Doc, Accept the permissions.
I am not sure if an add-on falls under the category Google Apps Script you were asking for, bug Text Factory provides the feature to insert a time-stamp.
Here is an edited version (of the one already provided) that prints out a date stamp including the time.
Here is an example of the output: 2:43:21 AM EST 26-03-2014
function onOpen() {
var ui = DocumentApp.getUi();
// Or FormApp or SpreadsheetApp.
ui.createMenu('Insert Date')
.addItem('Insert Date', 'insertDate')
.addToUi();
}
function insertTime() {
var d = new Date();
var timeStamp = d.getTime(); // Number of ms since Jan 1, 1970
// OR:
var currentTime = d.toLocaleTimeString(); // "12:35 PM", for instance
}
function insertDate() {
var cursor = DocumentApp.getActiveDocument().getCursor();
if (cursor) {
// Attempt to insert text at the cursor position. If insertion returns null,
// then the cursor's containing element doesn't allow text insertions.
var d = new Date();
var dd = d.getDate();
dd = pad(dd, 2)
var mm = d.getMonth() + 1; //Months are zero based
mm = pad(mm, 2)
var yyyy = d.getFullYear();
var timeStamp = d.getTime(); // Number of ms since Jan 1, 1970
var currentTime = d.toLocaleTimeString(); // "12:35 PM", for instance
var date = currentTime + " " + dd + "-" + mm + "-" + yyyy;
var element = cursor.insertText(date);
if (element) {
element.setBold(true);
} else {
DocumentApp.getUi().alert('Cannot insert text at this cursor location.');
}
} else {
DocumentApp.getUi().alert('Cannot find a cursor in the document.');
}
}
function pad (str, max) {
str = str.toString();
return str.length < max ? pad("0" + str, max) : str;
}
If you want to get automatically current date after open document, you can add this script:
In Google Docs: Tools -> Open Script Editor and save this script:
/**
* After open document actualize part with text "Generated" to "Generated [actual date]".
*/
function onOpen() {
var body = DocumentApp.getActiveDocument().getBody();
var date = Utilities.formatDate(new Date(), "GMT", "dd.MM.yyyy");
// Clear the text surrounding "Apps Script", with or without text.
body.replaceText("^Generated.*$", "Generated " + date);
}
In the document body you must have text "Generated".
Create a new Sheets document
In A1, put Date: and B1, put the formula NOW(). I named the sheet current-date, but you can name it whatever you want. This document will simply sit on your drive to server as a "date keeper" for all of your Docs documents.
Format Cell as Date
Select cell B1 and choose Number >> Date from the Format menu.
Select Cells and Copy
Select cells A1 and B1, right click, and choose Copy
Paste and Link to Docs Document
Right click in your Docs document where you want to paste the cells and click Paste. Docs should ask you if you want to link these cells to the source document. Select Link to spreadsheet and then click Paste.
Get Rid of the Borders
To get rid of the borders, right click on the inserted cells and select Table Properties.
Now set Table Border to 0pt and click OK.
Final Result
You should end up with something like this. You can drag the edges of the cells to make them bigger or smaller and change the font and text size of the cells as well. If you make the text bigger, the text will wrap inside the cells so you will need to make them wider.
Updating the Date
Now whenever you open your document with the linked cells and the date has changed, you should see this. Click Update and your date will be updated to today's date. There is no need to ever open the current-date spreadsheet!
Enjoy!
For Docs, you are probably out of luck, as there appears to be no hotkey for that, and support for scripting from within Docs is lacking (Spreadsheets would be a different story). Since you're on Windows, you can avail yourself of autohotkey, though. This video, while way too long, shows assigning a global hotkey combo to insert the current date anywhere. With that, you can insert your date/time anywhere you want to while using your Windows system. (You can customize it to be only active in certain applications, such as IE, if you want to get wacky with it)
Because extra key-strokes are being used to insert the date from the menu, my solution is a batch file, sts.cmd, that stores the date-time into the clip-board when called, enabling an easy Windows+R, sts, Ctrl+V to get and paste. If you are adding extra keystrokes to get the date into the doc anyway you might as well just paste it in.
The code is
#ECHO OFF
for /f "tokens=1-12 delims=/:. " %%d in ("%time%") do SET MYTIME= %%d:%%e:%%f
for /f "tokens=1-12 delims=/:. " %%d in ("%date%") do SET MYDATE= %%g-%%e-%%f
SET MYTS=%MYDATE%%MYTIME%
ECHO | SET /p dummyname=%MYTS%|clip
This works for me until GDocs comes up with an embeddable function that will update the display date to the current date each time the doc is opened.
On MacOS, I used Automator.
I created a Service that works with Chrome, takes no input, and runs a shell script and sends the output to the clipboard. The shell script is very basic:
DateTime=`date "+%Y-%m-%d %H:%M"`
echo $DateTime
I could have done without the intermediate variable and just run the date command, but I had the idea that I might want to do extra processing and formatting. Note that if you want to include spaces in your formatting of the date string, the formatting argument must be in quotes. The screen shot uses an underbar instead.
With the script saved, I went to System Settings > Keyboard > Shortcuts, I found my script DateTime2CB.workflow in the Text section and gave it a hotkey. There's no easy way of finding out what hotkeys are in use.
I could have made it for any app (and if I find myself trying to use it other apps I still might do that), but for now it's Chrome only. I could also have had the shell script pipe the output of date to the clipboard, pbcopy on Mac, as above (using "clip"). I've tested both methods and they work.
I added the same script to another Mac and it was set up to insist that the Automator file (name.workflow) be saved in iCloud. in that context, it was not listed in the Keyboard settings. To fix that, I had to reopen the saved iCloud file in Automator using Open > Recent. It asked if I wanted to install the file in Services. A yes answer at that point saved it on my local system and I could find it under Settings > Keyboard > Shorcuts > Services.
I hope this helps other Mac users.
August
Try this:
function insertTimestamp() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveCell();
cell.setValue(new Date());
// sets the cells format to month/day/year.
// Remove if you want time inserted as well
cell.setNumberFormat("MM/dd/yyyy")
}
This works on spreadsheets not sure if you were looking for other docs.
Create a Spreadsheet Today in google docs. Put the date in B1 as Today() Format it in C1 using the function Text(B1,"dddd, mmmm d, yyyy")
Then use the following script (you will need the url of the Today Spreadsheet
function myFunction() {
var doc = DocumentApp.getActiveDocument();
var body1 = doc.getBody();
var style1 = {};
style1[DocumentApp.Attribute.BOLD] = true;
var text1 = doc.editAsText();
body1.appendHorizontalRule();
var wb = SpreadsheetApp.openByUrl('spreadsheet url');
var ss = wb.getSheetByName('Today');
var r = ss.getRange('C1');
var date1 = r.getValues();
var par1 =body1.appendParagraph(date1[0]);
par1.setAttributes(style1);
}