Running scripts resetting active cell - google-apps-script

I'm fairly new to Google Scripts, and I'd like to use onEdit to trigger a function whenever a cell is edited. While I've got it working, it resets the active cell to A1 when it runs, so if someone tries to enter more than one value at a time, e.g. cells C4, D4, E4) - while they are entering a value into E4 the selection will reset to A1.
Cheers
Edit: Here's a spreadsheet showing the problem.
On further inspection, it looks like running any script (I also have a delete row function and an insert row function) will reset active cell to A1. This may not be the technical term, but if you have for example D4 selected, then running a script will change selection to A1

In your code, you're resetting the active sheet, which reloads the page when the script is triggered.
Here's your current code:
// Get the active workbook
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Get the first sheet in the workbook
var sheet = ss.getSheets()[0];
// Reload that first sheet
SpreadsheetApp.setActiveSheet(ss.getSheets()[0]);
Remove the third line where .setActiveSheet() is called and the problem will go away.

Related

setFormula() in a FormResponse Sheet

I am using GAS to generate a Google Form via Google Sheets. After the Form is generated and the "Responses" tab is added to the Sheet, the script adds a formula to cell E1 that is just supposed to copy the Timestamp from the A column to the E column. It looks like this:
ss.getSheets()[0].getRange("E1").setFormula("={\"Timestamp Moved\"; ARRAYFORMULA(IF($A$2:$A<>\"\",$A$2:$A,\"\"))}");
And shows this in the cell:
={"Timestamp Moved"; ARRAYFORMULA(IF($A$2:$A<>"",$A$2:$A,""))}
The formula drops into place just fine and looks right when I go to the Sheet and click on E1. However, whenever the Form is submitted, the "A$2:$A" moves down one row. So after the first submission, the formula in E1 changes to:
={"Timestamp Moved"; ARRAYFORMULA(IF($A$3:$A<>"",$A$3:$A,""))}
And so on. However, if I go into E1 and manually type the formula ={"Timestamp Moved"; ARRAYFORMULA(IF($A$2:$A<>"",$A$2:$A,""))} it works just fine. The A2 will stay A2 across all submissions.
The setFormula function is only running once, so it isn't like the GAS script is updating it. Any ideas why it is moving itself down?
EDIT
To minimally reproduce this, open GAS from within a Google Sheet and add this script:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.getSheets()[0].getRange("C1").setFormula("={\"Timestamp Moved\"; ARRAYFORMULA(IF($A$2:$A<>\"\",$A$2:$A,\"\"))}");
}
Next, from within the Sheet, select "Tools" and "Create a new form". Make a one question Form, then run the script. Go to the Responses tab and you should see this:
Then, fill out the Form once and you will now see this:
The timestamp is not moved and the formula shifts.
Google form response is inserted right after the row of the last response.
So the range changes from A2:A tp A3:A.
You should either add the formula after there is a response in row 2,
or use INDIRECT("A2:A") instead of A2:A.

Why isn't my time based trigger working properly?

I recorded a simple google sheets macro ( relative reference ) by copying info within a cell and pasting it into the cell below. It works fine when a manually run the macro but when I added a time based trigger ( every minute ) it only runs on the cell "A1" and not the selected cell e.g. B2.
I need the time based trigger so that it works for the selected cell instead.
function copy1() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet= SpreadsheetApp.getActiveSheet()
spreadsheet.getCurrentCell().offset(1, 0).activate();
spreadsheet.getCurrentCell().offset(-1, 0).copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
};
Seems like when it automatically runs, the initial cell is A1. You can overwrite that by saying offset(2,2) on line 4 of your code. Then it should always use that cell. Remember that if you create a relative reference that the currently selected cell will not necessarily be selected when the trigger is running.
UPDATE: The time-driven trigger cannot retrieve the current cell
Why?
Because a time-driven trigger runs even if the spreadsheet is closed - in this case there is no current cell, but by default Google Sheets always resets the current cell to A1 when you reopen the spreadsheet - this is the one the tie-driven trigger retrieves.
Good news: Recently a new trigger has been introduced - onSelectionChange(e)
This trigger fires every time you change the selection.
So for example if you click away from A1 to B2 - B2 will be detected as the new selected cell with the event object e.range.
Sample:
function onSelectionChange(e) {
var cell = e.range;
cell.copyTo(cell.offset(1, 0), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
}

Prevent a function in Google App Scripts from updating on a cell edit

I am trying to sort a list of 32 names in column A randomly to column B, I found this formula to do this:
=sort('Sheet1'!A2:A33,arrayFormula(randbetween(sign(row('Sheet1'!A2:A33)),100)),true)
This works great, but I then want to be able to use the new/random list in column B to use in other formulas. The problem is that any time you update any cell (even on another sheet) the list re-randomizes, preventing me from using any of the cells from the random list.
So I tried to take the formula out of the cell it was in and putting the formula in a menu option, thinking it would prevent the sheet/cell from updating with this Apps Script:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Custom Menu')
.addItem('Menu1', 'menuOption')
.addToUi();
}
function menuOption() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var cell = sheet.getRange("B2");
cell.setFormula("=sort('Sheet1'!A2:A32,arrayFormula(randbetween(sign(row('Sheet1'!A2:A33)),100)),true)");
}
But it still re-randomizes the list in column B whenever a cell is edited. Is it possible to call a formula or App Script function only once, when ran?
Thanks,
Formulas inside cells update with every edit, for the problem you are having you must be calling it within a cell somewhere on the spreadsheet.
You need to remove this call and only run it via the scripts interface or the menu button.
or
If you don't mind wasting google server resources set a boolean value in a cell somewhere on your spreadsheet and check the value before you run the sorting aspect of the script.

Trigger a script when a formula changes a cell value

I'm using a Google script then sends out an email when a certain column in a Google sheet is changed. The information in the cell is either inputted manually, or completes using a formula based on information in other cells.
The script works fine when information is manually entered, but not when the formula runs. I've read up on it and realise that a formula calculation doesn't count as an edit, so how do I get the script to run?
It's currently set up to trigger from the spreadsheet when there's an edit.
Below is the part of my script that covers the column/cell in question.
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var row = sheet.getActiveRange().getRow();
var cellvalue = ss.getActiveCell().getValue().toString();
if(sheet.getActiveRange().getColumn() == 12)
There's a lot more included in the script so I haven't copied everything onto here. Many thanks in advance.
There is no trigger that can run when a formula changes.
Try figure out, what conditions is your formula depends on:
if it is another cell, entered manually, then use those cell to trigger it's changes with onEdit
if the formula imports data from external source, use random or time functions, you'd better use onTime trigger.
if the formula uses importrange then go to the range you import and see the original range, return to step 1 → 2...

CopyTo: How to push data/copy a cell from one google spreadsheet to another google spreadsheet using google apps script?

I look for a solution to copy a specific cell value in the Source spreadsheet from tab "Sum all" to another Spreadsheet to the Target Spreadsheet Tab "Copy all". It should work every time i change the Value of Cell G10. Access to the Target sheet is granted before i enter any Value to G10.
(Source Tab Name is "Sum all:G10" - Sheet has 10 different Tabs)
(Target Tab Name is "CopyData:T12" - Sheet has 10 different Tabs)
Easy way
Use the built-in IMPORTRANGE() function in Google Apps:
In your Target cell, type the following formula
=IMPORTRANGE("FILE_ID_HERE","Sum all!G10:G10")
The syntax for this function is
=IMPORTRANGE("FILE_ID","SHEET_NAME!RANGE_START:RANGE_END")
When you first type in this function, you'll get an error in the cell. Simply click on it and select "Allow" to link the two sheets together. This error will occur even if it is the same spreadsheet. This function can link two separate spreadsheets, too, as long as you have edit access to both.
Hard Way
I'm assuming from your question that you want to copy values to and from the same spreadsheet document, but to different cells that are located on different sheets of the spreadsheet. The Google Apps Script API calls tabs "sheets" and the overall document "spreadsheet".
First, open the script editor
Open your spreadsheet that you'd like to make this script for.
Select "Tools" in the toolbar, then "Script Editor"
Second, make a function for onEdit.
Making a function named onEdit will create a function that runs every time the edit trigger is fired, using a no-authorization "simple trigger". Google Sheets automatically sends this event every time a cell is edited by a user. The argument e for the function is the event passed by the trigger.
function onEdit(e) {
// Get the sheet named "Sum all" from the active spreadsheet (i.e. the one you are editing)
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sum all");
// Returns the active cell
var cell = source .getActiveCell();
// Compare to see if its the right cell you're looking for
// getRow and getColumn methods return integers for the row and column of the cell
// A = 1, B = 2, ... G = 7
if (cell.getRow() == 10 && cell.getColumn() == 7) {
// If its the right cell, copy to the other cell
var target = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CopyData");
// set the value of the desired cell in the target sheet
target.getRange("T12").setValue(cell.getValue());
}
}
Third, save the script
Save the script, reload the file, and test it out.
If your tabs are on different spreadsheets
Change this line:
var target = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CopyData");
to this:
var target = SpreadsheetApp.openById("FILE_ID").getSheetByName("CopyData");
and insert the file ID for the target spreadsheet where I've written FILE_ID.
You will also need to use an "installed trigger", since a simple trigger cannot open a remote spreadsheet. To do this, change the name (so it is no longer a simple trigger function), and follow the steps here