Run a script every time there is a change in a cell - google-apps-script

I want to run this sript every time there is a change in notes!C4 and automatically copy the value to notes!D4 cell
function Copy() {
var ss = SpreadsheetApp.getActive().getSheetByName("notes") ;
ss.getRange('notes!C4').copyTo(ss.getRange('notes!D4'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
}
Update 1
If this it can't be done, I have in another spreadsheet a script that copies the link http://openinsider.com/screener?s= every time I run it to L2 cell of that sheet.
I'm taking that value with an =ImportRange to the actual spreadsheet. How can I copy that link to notes!D4 that's in another spreadsheet to the actual one?
function Refresh() {
var ss = SpreadsheetApp.getActive().getSheetByName("sheet1") ;
var cell = ss.getRange("L2");
cell.clearContent();
SpreadsheetApp.flush();
Utilities.sleep(5000); // You have 5 second to check that the cell has cleared
cell.setValue('http://openinsider.com/screener?s=');
}
Update 2
I've tried this, the first time the script was charging but it didn't make anything. I'm new to google scripts and I don't know how to make it working.
function onEdit(e) {
if (e.range.getA1Notation() === 'C4') {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("notes").getRange('D4').CopyPasteType.PASTE_VALUES;
}
}

As mentioned by #Cooper, you just need to use onEdit(e) Simple Trigger to run your script whenever there is a cell being modified.
I will just refer on your latest update, you can refer to this sample code:
function onEdit(e) {
var ss = e.source;
var cell = e.range;
if(cell.getA1Notation() === "C4" && ss.getActiveSheet().getName() == "notes"){
ss.getActiveSheet().getRange("D4").setValue(e.value);
}
}
What it does?
Get the spreadsheet object using Google Sheets events source parameter
Get the range object using Google Sheets events range parameter
Check if the modified cell is in sheet notes and in cell C4, I get the sheet object using Spreadsheet.getActiveSheet() method and get its sheet name using Sheet.getName(). This will make sure that your function will only run when Sheet notes!C4 was modified.
Set the value of the cell D4 using Range.setValue(value). To maximize the event object, I used value parameter in Google Sheets events.
Additional Tips:
Please be mindful of the methods available in each classes/objects that you are using. For example in this code:
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("notes").getRange('D4').CopyPasteType.PASTE_VALUES;
You get the range object of cell D4 using Sheet.getRange(a1Notation)
range object doesn't have CopyPasteType.PASTE_VALUES in its methods

Related

Trigger when change is happening in specific sheet

I have a sheet with data that is imported through IMPORTRANGE to another sheet. When I make changes to Spreadsheet 1 >>> Spreadsheet 2 I have a script that copy the data from Copy to Paste. It is working all fine however I want to make sure that the script only runs when changes are made in the 'Copy' sheet and not any other. At the moment it runs independent on what sheet I make changes in.
Spreadsheet 1
Spreadsheet2
I tried onChange trigger two different ways...
This one makes the change but triggers when changes are made in any of the sheets
function Trigger2(e) {
var sheet = e.source.getActiveSheet();
if (sheet.getName() === 'Copy') {
copyInfo();
}
}
AND
(this does not work)
function Trigger2(e) {
var sheet = e.source.getActiveSheet();
var sheet = SpreadsheetApp.getActiveSpreadsheet();
if( sheet.getActiveSheet().getName() !== "Copy" ) return;{
copyInfo();
}}
The copy code looks like this...
function copyInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Copy");
var pasteSheet = ss.getSheetByName("Paste");
// get source range
var source = copySheet.getRange(2,1,12,8);
// get destination range
var destination = pasteSheet.getRange(2,1,12,8);
// copy values to destination range
source.copyTo(destination);
}
Copy Changes from one Sheet To Another after Imported Range Changes
Spreadsheet 2 Imports a range to Sheet1 from Spreadsheet 1 Sheet1 and when a change occurs in Spreadsheet 2 Sheet1 we copy data from Spreadsheet2 Sheet1 to Spreadsheet2 Sheet 2.
function onMyChange(e) {
//Logger.log(JSON.stringify(e));//useful during setup
//e.source.toast("Entry");//useful during setup
const sh = e.source.getSheetByName("Sheet1")
Logger.log(sh.getName());
if(e.changeType == "OTHER") {
let tsh = e.source.getSheetByName("Sheet2");
sh.getRange(2,1,12,8).copyTo(tsh.getRange(2,1));//Only need the upper left hand corner of the range. Thus you change change the size of the source data without having to change the target range.
}
}
One might be inclined to attempt to use e.source.getActiveSheet() unfortunately this does not necessary get the sheet that you have written unless in is SpreadsheetApp.getActive().getSheets()[0]. onChange event object always returns the most left sheet in the spreadsheet in this situation so it can't be used to identify the sheet that is being written to from the importRange function.
With this function you no longer require another function.
A simple if should work, but you're trying to compare the name to the wrong field. According to Google's documentation, the source field in the Event Object e returns the Spreadsheet object, which is the entire document.
Instead you can use the e.range field, which contains the exact range where the edit was made, and the Range class has a getSheet() method to get the parent Sheet.
So you can modify your sample to the following:
function Trigger2(e) {
var sheet = e.range.getSheet();
if (sheet.getName() === 'Copy') {//Edit: this will only work if sheet is the most left sheet in the spreadsheet
copyInfo();
}
}

Show/Hide Columns Using A Checkbox

I am a wanna-be developer who is trying to figure out how to hide a set of columns based off a checkbox being clicked.
Would anyone want to help with this code?
I have 12 different sheets(one for each month) and I would like to hide columns A-H with the checkbox in I being clicked.
Ideally I can implement on each individual sheet.
Link to spreadsheet
There are few ways one can do it.
Easiest and most recommended among all is to group those column and it will have pretty much same use which you're looking for.
If you're willing to use appscript for it. Here how it should be done:-
Open Script Editor from your spreadsheet.
Declare the onEdit simple trigger which will run every time when sheet will be edited.
So whenever you'll click on tickbox on I1 this function will trigger.
When a trigger fires, Apps Script passes the function an event object as an argument, typically called e.
For this object, we're gonna have the information we need to do our task, and also to restrict our operation to only to those months sheet and range belongs to it.
Here is the code, I tried my best to explain what happening in the code:-
function onEdit(e)
{
var rangeEdited = e.range; // This will us range which is edited
var sheetEdited = rangeEdited.getSheet().getName() // from range we can get the sheetName which is edited
var mySheets = ["Jan List","Feb List"] // Put all the month sheet name in this array where you want to have this functionality
var rowEdited = rangeEdited.getRow() // From Range we can get Row which is edited
var columnEdited = rangeEdited.getColumn() // From Range we can get Column which is edited
if(mySheets.indexOf(sheetEdited) > -1) // Now we want to only restrict the operation on those sheets,so if other sheet is edited, we shouldn't run our hide function
{
if(rowEdited === 1 && columnEdited === 9) // we're further restricting the range of operation to run this function when only I1 is edited that is Row:- 1 and Col:- 9
{
hideUnhide(sheetEdited) // calling our hide function within OnEdit and passing sheetName as an argument in it
}
}
}
function hideUnhide(sheetEdited) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssname = ss.getSheetByName(sheetEdited) // accessing the sheet which is edited
var isItHidden = ssname.isColumnHiddenByUser(1) // checking if range is already hidden
if(isItHidden === false) // if No, hide that range
{
ssname.hideColumns(1, 6)
}
else // if Yes, unhide that range
{
var hideThisRange = ssname.getRange('A:H')
ssname.unhideColumn(hideThisRange)
}
}
Documentation:-
AppScript Events

How to run script on specific sheet and insert a formula

I'm new and started learning to code this year.
I am trying to insert a formula into a specific sheet. The script is working and I am able to insert a new row and the formula, however the script runs even when I edit a different sheet. I only want it to run when cell A2 is edited on "Test" sheet.
Here is my code:
function onEdit(e) {
insertRow(e);
copyFormulas(e);
function insertRow(e) {
// get sheet
var sheet = SpreadsheetApp.getActive().getSheetByName("Test");
// Get the edited range
var editedRange = e.range;
if (editedRange.getA1Notation() === "A2") {
// check
sheet.insertRowBefore(2);
}
}
function copyFormulas(e) {
SpreadsheetApp
.getActive()
.getSheetByName('Test')
.getRange('C3')
.setFormula("=SUM(A3*B3)");
}
}
LINK to the sheet https://docs.google.com/spreadsheets/d/1AhwnzyKf6dSPHGKUPNuniZ0gtTihPDLaqAyEtAjNn8A/edit?usp=sharing
To accomplish this task, your code can be shortened to the following form
function onEdit(e) {
let range = e.range,
sheet = range.getSheet();
if (sheet.getName() == 'Test' && range.getA1Notation() == 'A2' ){
sheet.insertRowBefore(2);
sheet.getRange('C3').setFormula("=SUM(A3*B3)");
}
}
You can find a lot of useful information by reading the documentation on Event Objects Class Spreadsheet Class Range , or simply by searching for onEdit(e) on this site
I would add, sometimes instead of increasing the amount of formulas on the sheet (which causes the whole table to slow down), it is recommended to use an array formula that works for the whole column, and that you don't have to duplicate on every row.
In the case of your table, instead of adding a formula every time you insert a row with the following code sheet.getRange('C3').setFormula("=SUM(A3*B3)") - it is better to use one array formula in cell C1 ={"Col3";ArrayFormula(if(A2:A<>"",A2:A*B2:B,))}

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);

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.