Trigger a function on selecting a cell - google-apps-script

How to write a trigger which gets triggered everytime the user selects any cell. The trigger will call a function which would log the row number of the highlighted cell on Google Apps Scripts
I have already written a function which is doing that:
function getCell() {
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
//get the current highlighted cell
var cell = sheet.getCurrentCell();
//get the row number
var row = cell.getRow();
//log the value
Logger.log(row);
}
But I don't know how to write the trigger. Currently, I have to run the script every time I click on some other cell.

strange, it worked the first time....
function onSelectionChange(e){
Browser.msgBox('cell selection change');
}
maybe things have changed since the question was posted, but landed here.

The available triggers are described on https://developers.google.com/apps-script/guides/triggers/. An alternative that could serve as a workaround is to use the "poll technique" described on How do I make a Sidebar display values from cells?

Related

getActiveCell() always returns 1,1

I know this has been asked before but none of the answers seem to be working for me. I need to get the values of cells that are clicked on. As a very basic prototype, I created a script tied to my spreadsheet with the following:
function getVal() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
Logger.log(sheet.getActiveCell().getValue());
}
I then go into my spreadsheet and select a cell with a value and run the function in the script window. No value is displayed in the log.
Next I tried:
function getVal() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
Logger.log(sheet.getActiveCell().getRow() + ',' + sheet.getActiveCell().getColumn());
}
I then go into my spreadsheet and select a cell with a value (G6) and run the function in the script window. The log displays 1,1.
And finally I tried
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
Browser.msgBox(sheet.getActiveCell().getRow() + ',' + sheet.getActiveCell().getColumn());
}
I then go into my spreadsheet and select a cell with a value (G6) and make a change to it. When I hit enter, the popup dialog displays 1,1.
This seems like it should be really simple but for the life of me cannot figure it out. Can anyone help?
I tested this in a spreadsheet and I found that using var sheet = ss.getActiveSheet(); yielded the correct results whereas using the .getSheets()[] method did not.
This is a bit late, but I was researching this today, and wanted to share: My issue was similar, in that sheet.getActiveRange().getRow(), sheet.getActiveCell().getRow(), etc., all returned row 1, regardless of what cell or range was active.
In this case, I was opening the script from a previous bookmark I created. Opening the script from a bookmark apparently doesn't re-establish the active relationship with the sheet.
Once I opened the script from the spreadsheet instead, my code returned the correct row reference.
I have tried following code and works fine. getRow() method is of Range class not Sheet class.
var ActSpSheet = SpreadsheetApp.getActiveSpreadsheet();
var ActSheet = ActSpSheet.getActiveSheet();
var GetCell = ActSheet.getCurrentCell();
var GetCurRow = GetCell.getRow();
Logger.log(GetCurRow);

Google script, how to access and paste on edit to a specific sheet within another spreadsheet?

I am attempting to create a script so that when a change is made in one spreadsheet the corresponding sheet with the same name in another spreadsheet receives the same change in the same place, and so I can put one lot of the script in each one and get two linked sheets that affect each other.
this is the code:
var targetID = 'ID of the sheet';
var targetSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
function onEdit(e){
var range = e.range;
var value = e.value;
var row = range.getRowIndex();
var column = range.getColumnIndex();
exportValue(row,column,value)
}
function exportValue(row,column,value) {
//(**this is the point where it breaks**)
var s = SpreadsheetApp.openById(targetID).getSheetByName(targetSheet);
var target = s.getRange(row, column);
target.setValue(value);
}
In my version i put in logs in between each line to see where it failed and it got to the line where i have put "this is the point where it breaks" and then didn't return anything after that.
Since attempting this I tried to open up the other file by just pulling out all of the variables but I couldn't get it to work.
the current error messages that it is going with are:
Cannot find function getSheetByName in object Sheet
Cannot find function openById in object Spreadsheet
I have spent so much time on this already and I feel like the answer is really simple but I would really appreciate any advice
Thanks in advance
:)
Linked Spreadsheets with Installable onEdit() triggers
I got this to work by using an installable onEdit(e) Trigger.
function Linked1Edit(e){
var ss=SpreadsheetApp.openById('The Other Spreadsheets ID');
var sh=ss.getSheetByName(e.range.getSheet().getName());
var rg=sh.getRange(e.range.rowStart,e.range.columnStart);
rg.setValue(e.value);
}
I called one Linked1Edit(e) and the other Linked2Edit(e) and created an installable onEdit(e) trigger for each one and now they write to each other.
Unfortunately, it only works for single valued changes though.
The following script will allow you to make changes to more than one value at a time.
function Linked1Edit(e){
var ss=SpreadsheetApp.openById('The Other Spreadsheet ID');
var sh=ss.getSheetByName(e.range.getSheet().getName());
var rg=sh.getRange(e.range.rowStart,e.range.columnStart,e.range.rowEnd-e.range.rowStart+1,e.range.columnEnd-e.range.columnStart+1);
var vA=e.range.getValues();
rg.setValues(vA);
}
Event Object Link
Creating a Trigger
Select Current Project's Triggers
Click Add Trigger:
Create Trigger Dialog:
You can also create a trigger in code. See ScriptApp Class

On Google Form Submit clear cells of active row in Google Sheets

I'm quite new to google sheet script and looking for some assistance. I am trying to make a google script that will erase cells in a response sheet after a user has submitted it. As this could be a form edit url, it may not necessarily be the last row.
So everytime a form is submitted / edited, columns AN:AQ are cleared.
Any help greatly appreciated
I'm adding the working script to OP's question for anyone who comes across this.
function onFormSubmit11(e) {
var range = e.range;
var ss = range.getSheet();
var row = range.getRowIndex();
ss.getRange("AN"+row).clear();
ss.getRange("AO"+row).clear();
ss.getRange("AP"+row).clear()
ss.getRange("AQ"+row).clear()
}
The Spreadsheet trigger invoked by the Google Form contains the Range object. You can retrieve the sheet linked to the range as well the index of the row linked to the current form submission.
function formTrigger(e) {
var range = e.range;
var sheet = range.getSheet();
var rowIndex = row.getRowIndex();
sheet.getRange(rowIndex + 1, 1).setValue("Hello");
}
You could try something as simple as an onFormSubmit running the script through your linked spreadsheet. The script below will clear AN:AQ every time a form is submitted which is 'alf of what I think you're asking for.
As for on edit, that's something I'm trying to figure out myself in my own question!
function onFormSubmit() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sh = ss.getActiveSheet()
sh.getRange('AN1:AQ').clear();
}
Hi Again,
Try this below. As before, make sure your trigger is set on OnFormSubmit and it should work flawlessly. I've tested it myself, it only cleared the range between AN:AQ on row (wherever the form edits). If you want to delete different sections just replace the AN:AQ for whatever column(s) you wish to clear.
function onFormSubmit(e) {
var range = e.range;
var ss = range.getSheet();
var row = range.getRowIndex();
ss.getRange("AN:AQ"+row).clear();
}

How do I deselect an active cell when clicking on an image to run a script?

I have a spreadsheet-bound script that is invoked by clicking an image in the spreadsheet. I've found that the script can be blocked if a cell that it needs to modify is active or being edited by the user.
The code could be anything, even as something as simple as this:
function newf() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange("R4");
range.clear();
}
When the cell R4 is open, the function will ignore the cell.
How do I deselect an open cell when clicking on an image to run a script?
The easy (manual) solution would be to click off the open cell prior to clicking on the image, but I am trying to make the script fool-proof and this can be a costly concern. Is there any way that the function can forcefully deselect an active cell?
Edit: I do not mean active cell. Definitely "open cell." Here are pictures of the error.
Open cell with data being entered
Clicked on Picture, program ran
You can use Sheet.setActive() to move the attached user's cursor to a different location in the spreadsheet. You need to remember that there is a relationship between the User Interface and scripts invoked from it, which is what allows the script to determine and change the currently active cell. This does not extend to the multiple user case, though - if User1 is editing the guarded cell when User2 clicks to run the script, the script will have no idea about it.
function newf() {
var safePlace = "A1"; // Some safe cell
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var activeCell = ss.getActiveCell();
if (activeCell.getSheet() == sheet && activeCell.getA1Notation() == "R4")
sheet.setActiveSelection(safePlace);
var range = sheet.getRange("R4");
var activeCell = ss.getActiveCell();
if (activeCell.getA1Notation() == range.getA1Notation() && activeCell.getSheet().getName() == range.getSheet().getName()) {
// Move user from target cell
sheet.setActiveSelection(safePlace);
range.clear();
}
I had the same problems, both the initial one and with the solution proposed by Mogsdad.
I resolved it the following way:
Before running any of the script, the first three lines get a different sheet opened and the spreadsheet gets flushed:
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('DIFFERENT SHEET NAME'), true);
SpreadsheetApp.flush();
The rest of the script follows.
Then at the end of the script, I reopen the initial sheet with a simple:
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('ORIGINAL SHEET NAME'), true);
Another "solution" to this is not to use a button, but use a check mark as if it we a button, and use the onEdit function.
function onEdit(e)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
checkbox1 = ss.getRange("saveCheckbox_001");
if (checkbox1.isChecked())
{
submit1(); //do all the fun stuff associated with this checkbox
checkbox1.uncheck();
}
//more checkbox handling and calling other functions can go here if you need more than one "button"
}

Triggering script by specific cell value

I am pretty new to google sheets script development and am wondering how to trigger a clearAll script with cell value i.e. A1=100.
My clearAll script works (see below), though I don't know what to add to it to trigger it using a specific cell value.
function clearAll() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formresponses1 = ss.getSheetByName("formresponses1");
formresponses1.clearContents();}
Thanks
If you are trying to make it so that whenever somebody puts in the value of "100", it clears the content of the entire sheet, then you can do this:
function onEdit(e) {
var ss = SpreadsheetApp.getActive() //gets the active spreadsheet
var sheet = SpreadsheetApp.getActiveSheet() //gets the active sheet
var cell = ss.getActiveRange() //gets the active cell
var cellContent = cell.getValue() //gets the value of the active cell
if(cellContent === 100) {
sheet.clearContents() //clears the values of the entire active sheet
}
}
If you want to make it so that whenever somebody edits the cell and makes its value "100", the code clears only that cell, then do this:
function onEdit(e) {
var ss = SpreadsheetApp.getActive()
var sheet = SpreadsheetApp.getActiveSheet()
var cell = ss.getActiveRange()
var cellContent = cell.getValue()
if(cellContent === 100) {
cell.setValue("") //clears the value of the active cell
}
}
Of course, in the latter, due to the slight lag in Google scripts, if somebody rapidly puts in 100 in every cell they can, then some of the cells with a value of "100" will stay there, but if the person is putting the values in like a normal person rather than a spammer, then this code will work.
Also, if you are trying to make it so that if the value of a certain cell (ie: A1) is equal to "100," the script clears the entire sheet, do this:
function onEdit(e) {
var ss = SpreadsheetApp.getActive()
var sheet = SpreadsheetApp.getActiveSheet()
var cell = sheet.getRange('A1')
var cellContent = cell.getValue()
if(cellContent === 100) {
sheet.clearContents()
}
}
Hope I could help!
The onEdit trigger runs when any cell in the spreadsheet is edited.
Google Documentation - Spreadsheet On Edit
There is also a change trigger. It is an installable trigger, not a simple trigger.
Available types of triggers
Quote from documentation:
An installable change trigger runs when a user modifies the structure
of a spreadsheet itself — for example, by adding a new sheet or
removing a column.
I think the only thing that will work for you is the On Edit trigger. The trigger gets set from the Resources menu in the Apps Script Code editor.
I don't think you can restrict the code from running only to a certain cell, or a certain value within a cell. The code will run every time you edit ANY cell.
I think that the only other alternative would be to run a time based trigger, and have the script get the value of that cell, and check the value. The shortest time interval you can use is to run a script every minute. So if you edited the cell on second 1, it would take 59 more seconds before anything happened.
If you had some type of user interface, and the value in that cell was written to when the user entered a value in an input field, you could detect that change immediately, and make something happen.