I want to create a script that will display the cell address of the active cell in A1, however, this is proving difficult because I can't even get the onSelectionChange example on the Google Apps Script guide to work. Whenever I run it, the error I get is TypeError: Cannot read property 'range' of undefined.
This is the code:
/**
* The event handler triggered when the selection changes in the spreadsheet.
* #param {Event} e The onSelectionChange event.
*/
function onSelectionChange(e) {
// Set background to red if a single empty cell is selected.
var range = e.range;
if(range.getNumRows() === 1
&& range.getNumColumns() === 1
&& range.getCell(1, 1).getValue() === "") {
range.setBackground("red");
}
}
About your error message of TypeError: Cannot read property 'range' of undefined, I thought that you might have directly run the function of onSelectionChange with the script editor. If it's so, such error occurs because the event object e is not given.
onSelectionChange is used as the simple trigger. In this case, when you want to retrieve the cell address of the active cell with onSelectionChange trigger, please select the cell on Google Spreadsheet. By this, the script is run by the onSelectionChange trigger.
Sample script:
For example, when the onSelectionChange trigger is run by selecting a cell, the sample script that the cell address is put to the cell as the A1Notation is as follows. When you use this script, please copy and paste the following script to the script editor of Spreadsheet and save it. And, please select a cell on the active Spreadsheet.
function onSelectionChange(e) {
var range = e.range;
range.setValue(range.getA1Notation());
}
Result:
When above script is used, the following result is obtained. You can see that in order to run the script, the cell is selected.
Note:
Even when you selected a cell, when the sample script is not run, please close the Spreadsheet and open the Spreadsheet again. In my environment, I confirmed that by this, the onSelectionChange trigger worked.
Reference:
onSelectionChange(e)
Added 1:
About the following your replying,
Thanks. This works and so did the red cell Google example. Although I did have to close the workbook and reopen it to get it to work. How can I set the range to a fixed cell so the active cell address only appears there?
When you want to run the script for only the specific range, how about the following sample script? From your replying, I used your script for this.
Sample script:
function onSelectionChange(e) {
var ranges = ["A2:B5", "D2:E5"]; // Please set the range you want to run the script.
var range = e.range;
var sheet = range.getSheet();
var check = ranges.some(r => {
var rng = sheet.getRange(r);
var rowStart = rng.getRow();
var rowEnd = rowStart + rng.getNumRows();
var colStart = rng.getColumn();
var colEnd = colStart + rng.getNumColumns();
return (range.rowStart >= rowStart && range.rowEnd < rowEnd && range.columnStart >= colStart && range.columnEnd < colEnd);
});
if (check) {
range.setBackground("red");
}
}
In this script, only when the cell in the range of var ranges = ["A2:B5", "D2:E5"] is selected, range.setBackground("red") is run. So please modify ["A2:B5", "D2:E5"] for your actual situation.
If you want to also check the sheet name, please modify above script as follows. In this case, when the cell in the ranges ["A2:B5", "D2:E5"] of the sheet ["Sheet2", "Sheet3"] is selected, range.setBackground("red") is run.
function onSelectionChange(e) {
var sheetNames = ["Sheet2", "Sheet3"]; // Please set the sheet names.
var ranges = ["A2:B5", "D2:E5"]; // Please set the range you want to run the script.
var range = e.range;
var sheet = range.getSheet();
if (!sheetNames.includes(sheet.getSheetName())) return;
var check = ranges.some(r => {
var rng = sheet.getRange(r);
var rowStart = rng.getRow();
var rowEnd = rowStart + rng.getNumRows();
var colStart = rng.getColumn();
var colEnd = colStart + rng.getNumColumns();
return (range.rowStart >= rowStart && range.rowEnd < rowEnd && range.columnStart >= colStart && range.columnEnd < colEnd);
});
if (check) {
range.setBackground("red");
}
}
Added 2:
About the following your replying,
No, sorry. I meant how can I make the active cell address appear in A1. If I click on cell G5, for example, 'G5' appears in A1.
In that case, how about the following sample script?
Sample script:
function onSelectionChange(e) {
var range = e.range;
range.getSheet().getRange("A1").setValue(range.getA1Notation());
}
Related
In my Google Sheets, I'm trying to select cell A1 after my onSelectionChange Google Apps script executes, but even though the rest of the script executes, the selection doesn't change at the end. Selecting cell A1 is supposed to be done by the last three lines of code below. These three lines of code work fine in another script for another sheet, but for some reason they won't work in this even simpler script.
function onSelectionChange(e) {
// Insert date in a new cell, shifting existing cells down and then counting nonblank cells.
console.log("Start");
var range = e.range;
if(range.getColumn() >= 2
&& range.getColumn() <= 3
&& range.getNumRows() === 1
&& range.getRow() === 2)
{ var d = new Date();
range.offset(2,0).insertCells(SpreadsheetApp.Dimension.ROWS);
range.offset(2,0).setValue(d);
range.offset(1,0).setFormulaR1C1("counta(R[1]C[0]:C[0])");
var sheet = range.getSheet();
var cell = sheet.getRange("A1");
sheet.setCurrentCell(cell);
}
}
Try Using activate() Instead
activate() sets the specified range in getRange("<Range>") as the active range. For your script, you simply need to modify the last line to select cell A1 after the process triggered is done. It should look like this:
function onSelectionChange(e) {
// Insert date in a new cell, shifting existing cells down and then counting nonblank cells.
console.log("Start");
var range = e.range;
if(range.getColumn() >= 2
&& range.getColumn() <= 3
&& range.getNumRows() === 1
&& range.getRow() === 2)
{ var d = new Date();
range.offset(2,0).insertCells(SpreadsheetApp.Dimension.ROWS);
range.offset(2,0).setValue(d);
range.offset(1,0).setFormulaR1C1("counta(R[1]C[0]:C[0])");
var sheet = range.getSheet();
var cell = sheet.getRange("A1");
cell.activate(); //change done in this line.
}
}
Output
Reference
activate()
function setCalculate(){
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1M/edit#gid=0");
var srcSheet = ss.getSheetByName("AutoQuoteDataBase");
var lastRow = srcSheet.getLastRow();
var values = srcSheet.getRange("A2:BY" + lastRow).getValues();
var res = values.flatMap(r => r[76] == 1 ? [r[1]] : []);
if (res.length == 0) return;
srcSheet.getRange("BW2").setValue(res[0]);
}
This code works perfectly for its original purpose which was to copy IDs from Column B, say B2 is 'w131' and B3 is 'z1122', etc.
I needed Cell BW2 to be filled with one of these IDs if I put a '1' in column BY,
and it has to be the corresponding ID so putting a '1' in BY2 fills BW2 with 'w131' and putting a '1' in BY3 fills BW2 with 'z1122' etc.
What I need is for the same row to be moved from column BZ into CB2 when the code is triggered.
I believe your goal is as follows.
You want to copy the cell "B" to "BW" when the cell "BY" is edited to 1.
You want to run the script by a trigger.
In this case, how about the following modification?
Modified script:
Please copy and paste the following script to the script editor and save the script. When you use this script, please put 1 to the column "BY" of "AutoQuoteDataBase" sheet. By this, the script is run.
function onEdit(e) {
var range = e.range;
var sheet = range.getSheet();
if (sheet.getSheetName() != "AutoQuoteDataBase" || range.columnStart != 77 || range.getValue() != 1) return;
sheet.getRange("B" + range.rowStart).copyTo(sheet.getRange("BW" + range.rowStart), {contentsOnly: true});
Note:
This script is run by a simple trigger of onEdit. So when you directly run this script, an error like TypeError: Cannot read property 'range' of undefined occurs. Please be careful about this.
For example, when you want to copy the column "B" to the column "BW" by checking the column "BY" without using onEdit, you can also use the following script. In this case, you can directly run this function with the script editor.
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = ss.getSheetByName("AutoQuoteDataBase");
var lastRow = srcSheet.getLastRow();
var values = srcSheet.getRange("A2:BY" + lastRow).getValues();
var res = values.map(r => [r[76] == 1 ? r[1] : null]);
if (res.length == 0) return;
srcSheet.getRange("BW2:BW" + (res.length + 1)).setValues(res);
}
Reference:
Simple Triggers
Using the code below I am able to generate a hyperlink to each page within my googlesheet, with the name of that sheet:
/**
* Gets the Sheet Name of a selected Sheet.
*
* #param {number} option 0 - Current Sheet, 1 All Sheets, 2 Spreadsheet filename
* #return The input multiplied by 2.
* #customfunction
*/
function SHEETNAME(option) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet()
var thisSheet = sheet.getName();
var thisgid = sheet.getSheetId();
//Current option Sheet Name
if(option === 0){
return thisSheet;
//All Sheet Names in Spreadsheet
}else if(option === 1){
var sheet1 = [];
ss.getSheets().forEach(function(val){
sheet1.push(`=HYPERLINK("#gid=${val.getSheetId()}","${val.getName()}")`)
});
return sheet1;
//The Spreadsheet File Name
}else if(option === 2){
return ss.getName();
//Error
}else{
return "#N/A";
};
};
function GETLINK(option) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(option);
if (sheet != null) {
return(sheet.getId());
};
};
This returns a column of appropriate functions in each cells but does not evaluate the function. If I copy the function into another cell it does evaluate?!
=HYPERLINK("#gid=XXXXXXXXXXXXX","SHEET1")
I've tried also tried adding HTML but this also becomes a string and is not evaluated
sheet1.push(`${val.getName()})
When the custom formula of =SHEETNAME(0) is put to a cell, you want to put the sheet name of the active sheet on the Spreadsheet.
When the custom formula of =SHEETNAME(1) is put to a cell, you want to put the formulas of =HYPERLINK("#gid=XXXXXXXXXXXXX","SHEET1") for all sheets.
When the custom formula of =SHEETNAME(2) is put to a cell, you want to put the Spreadsheet name of the active Spreadsheet.
If my understanding is correct, how about this answer?
Issue and workaround:
Unfortunately, in the current specification of Google side, the formula cannot be put to a cell by the custom formula. When the formula is put to a cell by the custom formula, the formula is put as the string value. I think that this is the reason of your issue.
As a workaround, I would like to propose to put the formula of =HYPERLINK("#gid=XXXXXXXXXXXXX","SHEET1") using the OnEdit event trigger when the custom formula of =SHEETNAME(#) is put to a cell. I think that by this workaround, your goal can be achieved.
When your script is modified, please modify as follows.
Modified script:
In this case, the simple trigger can be used. So please copy and paste the following script to the script editor, and save the script. In order to use this script, as a test, please put =SHEETNAME(1) to a cell.
function onEdit(e) {
const spreadsheet = e.source;
const range = e.range;
const sheet = range.getSheet();
const formula = range.getFormula();
const f = formula.match(/\=SHEETNAME\((\d+)\)/i);
if (f && f.length > 0) {
if (f[1] == "0") {
range.setValue(sheet.getSheetName());
} else if (f[1] == "1") {
var formulas = spreadsheet.getSheets().map(val => [`=HYPERLINK("#gid=${val.getSheetId()}","${val.getName()}")`]);
range.offset(0, 0, formulas.length, 1).setFormulas(formulas);
} else if (f[1] == "2") {
range.setValue(spreadsheet.getName());
}
}
}
In this case, there is the function of SHEETNAME() in your script editor. So when =SHEETNAME(1) is put to a cell, at first, the function of SHEETNAME() is run, and then, the function of onEdit is automatically run by the OnEdit event trigger. If you don't want to show the values from SHEETNAME(), please replace the function of SHEETNAME() as follows.
const SHEETNAME = () => "";
Note:
In this case, when you directly run the function of onEdit at the script editor, an error occurs. Please be careful this.
This script is run under V8.
References:
Simple Triggers
Event Objects
setFormulas()
I have created the script below, which runs from an onedit function for when cell J1 is edited. The graph exists in the sheet titled 'Daily Data'. The data it will be using is from a sheet titled 'Long Term Data'.
I used the following link as guidance: https://developers.google.com/apps-script/reference/spreadsheet/embedded-chart.
Thank you for any help.
function onEdit(e) {
//This IF statement ensures it will only run when cell J1 is edited:
if (
e.source.getSheetName() == "Daily Data" &&
e.range.columnStart == 10 &&
e.range.columnEnd == 10 &&
e.range.rowStart >= 1 &&
e.range.rowEnd <= 1
) {
var spreadsheet = SpreadsheetApp.getActive();
var daily_data = spreadsheet.getSheetByName("Daily Data");
var LTD_data = spreadsheet.getSheetByName("Long Term Data");
//ABOVE HAS BEEN TESTED AND RUNS SUCCESFULLY. THE BELOW DOES NOT...
var chart = daily_data.getCharts()[0];
var range = LTD_data.getRange("B2:J3")
chart = chart.modify()
.addRange(range)
.build();
spreadsheet.updateChart(chart);
}
}
;
You want to update chart in the sheet of Daily Data using Google Apps Script.
If my understanding is correct, how about the following modification?
Modification point:
updateChart() is the method of Class Sheet. But in your script, updateChart() is used for Class Spreadsheet. By this, the script doesn't work.
When above point is reflected to your script, it becomes as follows.
Pattern 1:
In this pattern, the range is added to the existing ranges.
Modified script:
From:
spreadsheet.updateChart(chart);
To:
daily_data.updateChart(chart);
Pattern 2:
In this pattern, the existing ranges are removed and new range is added.
Modified script:
From:
var chart = daily_data.getCharts()[0];
var range = LTD_data.getRange("B2:J3")
chart = chart.modify()
.addRange(range)
.build();
spreadsheet.updateChart(chart);
To:
var chart = daily_data.getCharts()[0];
var range = LTD_data.getRange("B2:J3")
var ranges = chart.getRanges();
chart = chart.modify();
ranges.forEach(function(range) {chart.removeRange(range)});
var modifiedChart = chart.addRange(range).build();
daily_data.updateChart(modifiedChart);
Note:
In above case, the simple trigger of OnEdit event trigger can be used.
References:
updateChart(chart)
removeRange(range)
If I misunderstood your question and this was not the result you want, I apologize.
Please see example picture below.
I would like to use Google Sheets script editor to add a Filter view on cell B3, that filters on a custom formula =(B4=$B$1).
The plan is to add a onEdit function that checks whether the value in cell B1 has changed, and if so reset the filter view in cell B3.
This is breaking my brain! I can't seem to find a way to auto update/refresh the filter once my value in B1 has changed.
My code currently looks like this, but this doesn't re-add the custom formula. It just keeps showing me all the non-empty rows.
function onEdit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheetname = "Lactation";
var sheet = ss.getSheetByName(sheetname);
var erow = e.range.getRow();
//Logger.log("DEBUG: row = "+erow);
var ecolumn = e.range.getColumn();
//Logger.log("DEBUG: column = "+ecolumn);
if (erow == 1 & ecolumn == 2 ){
// there is a match so the cell is B2
//Logger.log("DEBUG: the cell is B2");
updatefilter();
}
else
{
// there is no match so the cell is NOT I3
//Logger.log("DEBUG: the cell is not I3");
}
}
function updatefilter() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('B3').activate();
var criteria = SpreadsheetApp.newFilterCriteria()
.setHiddenValues(['', 'No'])
.build();
spreadsheet.getActiveSheet().getFilter().setColumnFilterCriteria(2, criteria);
};
You want to modify the basic filter of the cells "B3:B" when the cell "B1" on the sheet Lactation is edited.
In this case, you want to use the OnEdit event trigger.
You want to use =(B4=$B$1), which is the custom formula, as the filter condition.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification points:
You can take advantage of the event object as e of onEdit(e).
In order to use the custom function for the basic filter, you can use whenFormulaSatisfied.
Modified script:
In order to run the script, please edit the cell B1 on the sheet Lactation.
function onEdit(e){
var sheetName = "Lactation";
var editCell = "B1";
var range = e.range;
var sheet = range.getSheet();
if (range.getA1Notation() == editCell && sheet.getSheetName() == sheetName) {
updatefilter(sheet);
} else {
// do something
}
}
function updatefilter(sheet) {
sheet.getRange('B3').activate();
var criteria = SpreadsheetApp.newFilterCriteria().whenFormulaSatisfied("=(B4=$B$1)").build();
var filter = sheet.getFilter();
if (!filter) {
filter = sheet.getRange("B3:B").createFilter();
}
filter.setColumnFilterCriteria(2, criteria);
};
In this script, when the cell "B1" on the sheet of Lactation is edited, the function updatefilter is run by the OnEdit event trigger. And when the basic filter is existing, it is updated. When no filter is existing, the filter is set as new filter. The range of the filter is "B3:B". The custom function of =(B4=$B$1) is used as the criteria.
Note:
In above script, the simple trigger can be used. But if you use the methods for requiring to authorize, when an error occurs, please try to use Installable Triggers.
References:
Simple Triggers
Installable Triggers
Event Objects
whenFormulaSatisfied(formula)
If I misunderstood your question and this was not the direction you want, I apologize.