Google app script - Getting last sheet row updated - google-apps-script

I have a script associated with a google sheet that it's call after a Google form is submitted.
Actually I can get all rows or the last but in case one form answer is updated I need to find this row updated to make my treatment.
Is there a way to do that?
This is my two case:
// Getting last row data
function getSpreadSheetLastRowData() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var row = sheet.getLastRow();
return sheet.getRange('A'+row+':BG'+row).getValues();
}
// Getting all rows data
function getSpreadSheetAllData() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var row = sheet.getLastRow();
return sheet.getRange('A2:BG'+row).getValues();
}

You will need to write an event handler for the onFormSubmit event object and attach it to your spreadsheet.
From the Spreadsheet linked to your Form go to Tools > Script Editor.
Here write a function to install the trigger:
function installTriggerToSpreadsheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ScriptApp.newTrigger('sumbissionHandler')
.forSpreadsheet(ss)
.onFormSubmit()
.create();
}
Now your trigger will handle the form submission calling the submissionHandler function inside the Spreadsheet context.
This means you can read the affected row by using a function like this:
function submissionHandler(e) {
var affectedRow = e.range.getRow();
// ... Apply your treatment.
}
References:
Triggers
Event Objects

If you have a script that is triggered by a form submission then take the event object lets call it e. Then e.range is the range that was edited in the linked sheet. So e.range.getRow() is the row and e.range.getSheet().getName() is the name of the linked sheet.
form submit object for spreadsheet

Related

Function based trigger using Sheet instead of Spreadsheet failing

I have two form feeding into the same sheet and I need different triggers for each sheet.
Tried to trigger using function based triggers but that is not working.
This function works:
function testTrigger() {
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)
.onChange()
.create();
}
This one fails:
function testTriggerTwo() {
var sheet = SpreadsheetApp.openById("...").getSheetByName("Responses");
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)
.onChange()
.create();
}
with
"Exception: The parameters (SpreadsheetApp.Sheet) don't match the method signature for ScriptApp.TriggerBuilder.forSpreadsheet."
Any ideas?
function testTrigger() {
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)//this sheet is a class Spreadsheet
.create();
}
This one fails:
function testTriggerTwo() {
var sheet = SpreadsheetApp.openById("...").getSheetByName("Responses");
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)//this sheet is a class Sheet
.onChange()
.create();
}
One of the problems in dealing with Google Apps Script and Google in general is that the people that sell products decided to begin to use the term Sheet as being synonymous with Spreadsheet but in the Apps Documentation Sheet refers to Excel like worksheet and I guess Spreadsheet refers to the excel like workbook. One is the file and the other is a tab. In the second version of the function you are using a Class Sheet when you should be using a Class Spreadsheet.
I would recommend using something like this for trigger creation to avoid the possibility of creating more that one trigger for any given function which can produce issues that are hard to debug.
function testTrigger() {
const ss = SpreadsheetApp.getActive();
if (ScriptApp.getProjectTriggers().filter(t => t.getHandlerFunction() == "myFunction").length == 0) {
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(ss)
.onChange()
.create();
}
}
By checking that none of the project project triggers have a handler with the same function name you can insure that you don't have two triggers for the same function.
You can control it by getting the the sheet name (where the response is landing)
function onFormSubmit(e) {
var sheet = e.range.getSheet().getName();
//do whatever you want by comparing the sheet name
}
You can have only one onFormSubmit Trigger.
But, you can do different things by an if statement

onEdit specific cell copy data from one google sheets to another

In google sheets, I am trying to get one data to copy from one sheet to another.
I have this code which is working however I would like it to run onEdit when changing cell E4 in Googlesheet1. I am new at this and doesn't seem to get it to quite work with the solutions I found online.
function ExportRange() {
var destination = SpreadsheetApp.openById('googlesheet1');
var destinationSheet = destination.getActiveSheet();
var destinationCell = destinationSheet.getRange("AC3");
var cellData = '=IMPORTRANGE("https://docs.google.com/spreadsheets/googlesheet2", "AE10:AE9697")';
destinationCell.setValue(cellData);
}
Chose between a simple and installable onEdit trigger, depending on your requirements
For most applciaitons a simple onEdit trigger is sufficient, to use it you just need to rename your function ExportRange() to onEdit()
Take advantage of event objetcs that give you informaiton about the event that fired the trigger
So, the trigger onEdit can give you among others information about the event range - that is the range that has been edited
Now you can implement an if statement to specify that the rest of the funciton shall only be run if the event range and the corresponding sheet are as required
Sample:
function onEdit(event) {
var range = event.range;
var sheet = range.getSheet();
if(range.getA1Notation() == "E4" && sheet.getName() == "Googlesheet1"){
var destination = SpreadsheetApp.openById('googlesheet1');
var destinationSheet = destination.getActiveSheet();
var destinationCell = destinationSheet.getRange("AC3");
var cellData = '=IMPORTRANGE("https://docs.google.com/spreadsheets/googlesheet2", "AE10:AE9697")';
destinationCell.setValue(cellData);
}
}
Please note that this function can only be fired by the trigger in
case of an edit. If you try to run it manually, it will give you an
error because event (and thus event.range) will be undefined if
the funciton was not called by an edit event.

Unwanted multiple row entries / copies (Google Form --> Google Sheet file, sheet1 --> Google Sheet file, sheet 2)

I've written an apps script in GSheet to:
Copy the last row of the Google Form sheet in Google Sheet file if a new entry arrived (trigger) by Google Form
Paste this row to another sheet in the same GSheet file to the last row
Unfortunately it copies the last row of the Form sheet more than one time to the appropriate sheet. Sometimes two times, sometimes four times. I cannot see my mistake in the code.
I couldn't find a solution so far. I included a pause before appendRow with Utilities.sleep(5000) but w/o effect.
function myFunction() {
// Source sheet: Form is the source sheet of the Google Form
var source =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form");
// Get last row in Form
var lastrow = source.getLastRow();
// Get just the date of the Form input
var formdate = source.getRange(lastrow,7,1,7).getValue();
// Change month number to string (e.g. April)
var currentD2 = Utilities.formatDate(formdate,
Session.getScriptTimeZone(), "MMMMM");
// Identify target sheet in same Google sheet file
var target =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(currentD2);
// Identify the appropriate range of the last row of the Form sheet
// (source)
var sourceData = source.getRange(lastrow, 2,1,8).getValues();
// Append the last row of the Form sheet to the last row in the target
// sheet
target.appendRow(sourceData[0])
}
I expect that the function copies just one time the last row of the Form sheet and not multiple times.
Hello I guess that you are using an onEdit trigger to start your function.
That means that when you change the "Google Form sheet" it triggers your function which changes another sheet in the same spreadsheet which starts your trigger again.
I recommend to rename your function onEdit(e)
ref(https://developers.google.com/apps-script/guides/triggers/events)
and then condition your action with: if e.range belongs to your "google form sheet" then do something otherwise not.
function onEdit(e) {
if (e.range.getSheet().getName()='your google form sheet') {
// insert here the contents of your function
}
}
you can use either this :
function appendEntry(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var ws = ss.getSheetByName("data") // this is the sheet where new entry arrive
var ws2 = ss.getSheetByName("target") // this is the sheet where the entries will go
var data = ws.getDataRange().getValues()
var data2 = ws2.getDataRange().getValues()
for(var i=0;i<data.length;i++){
var row = data[i]
for(var k=0;k<data2.length;k++){
var row2 = data[k]
if(row2[0] != row[0]){
} // This will loop through both sheet
// If entry is already mentioned in other sheet the data will not append
}
}
ws2.appendRow(data[k]) //other wise entry will append to the next sheet
}

Trigger when user switches between sheets

Is there a way on to run a script whenever the user switches between sheets in a Google Sheets Spreadsheet?
More or less like onOpen, but instead of running when the document is opened, it should fire every time the user switches to another sheet.
Here is my work-around for onSheetChange:
function saveActiveSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var actsheet = ss.getActiveSheet();
// The onSelectionChange() function executes in a separate thread
// which does not use any script global variables, so use the
// PropertiesService to maintain the user global state.
var userProperties = PropertiesService.getUserProperties();
userProperties.setProperty('ACTIVE_SHEET', actsheet.getSheetName());
}
function onSheetChange(e) {
// Do anything needed after a new sheet/tab selection
}
function onSelectionChange(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Get current sheet name and compare to previously saved sheet
var currentactsheet = ss.getActiveSheet();
var currentactsheetname = currentactsheet.getSheetName();
var userProperties = PropertiesService.getUserProperties();
var actsheetname = userProperties.getProperty('ACTIVE_SHEET');
if (currentactsheetname !== actsheetname) { // New sheet selected
saveActiveSheet();
onSheetChange(e); // Call custom sheet change trigger
}
// Do anything needed when a different range is selected on the same sheet
else {
var range = e.range;
}
}
function onOpen(e) {
saveActiveSheet();
}
UPDATE: On April 2020 Google added onSelectionChange(e) which could be used to check if the user switched between sheets aka tabs.
At this time there isn't a trigger related to switch for one sheet to another. To learn about the available triggers in Google Apps Script, please checkout Triggers and events - Google Apps Script Guides
As a workaround you could a custom menu to and SpreadsheetApp.setActivesheet to switch between sheets by using a script instead of using tabs and including in that script a call to the function to be run when switching from one sheet to another.
I have created a "Feature request" to implement "onSheetChange" trigger at google issue tracker. You can star it, so google now you want this:
https://issuetracker.google.com/issues/72140210
And here is related question with possible workaround: How to capture change tab event in Google Spreadsheet?
you can use
sheet1.showSheet();
sheet2.hideSheet();

Is it possible to send the google spreadsheet data to another application without using button click event?

I want to send the google sheet data to another application, using any trigger like onEdit. i am now able to send the data on a button click event, but now i want to do this without using any button little more automatic. it should be done just on cell edit.i've tried this can anybody please help.
var ss = SpreadsheetApp.openById("#########################");
function createSpreadsheetEditTrigger() {
ScriptApp.newTrigger('cellTracker')
.forSpreadsheet(ss)
.onOpen()
.create();
}
function cellTracker(){
var cell = ss.getActiveCell().getCellValue();
if((ss.getActiveCell().getValue()) > 0 && (ss.getActiveCell().getValue()) == Cell){
var link = app.createAnchor('XXXXX',"http://###############/noetic_Data/AddDataToAras?data="+Cell);
}
}
Instead of calling a spreadsheet by id, you could in this case attach a script to a spreadsheet by opening Tools -> Script editor -> Blank Project. This will open the script editor where you can use the onEdit trigger with this code:
function onEdit(e){
var myRange = e.range; //get the range that's edited
var myValue = myRange.getValue(); //get the value of the first cell in the range
//send data to other application
}
Every time you update a range (mostly just one cell) in your spreadsheet, this trigger wil use the event object containing the range and it's data.
https://developers.google.com/apps-script/guides/triggers/events
To see what's going on you can use the logger. For example:
Logger.log(myValue);