Bringing the cell's location rather than it's value - google-apps-script

I'm trying to create a custom formula for Google Sheets using Apps Script. The function will return the Hexadecimal background color of the cell (e.g. =getHEX(B1) will return the color of cell B1).
My problem is that I can bring the value of the cell, not the location. If I use quotes in the function it works (=getHEX("B1")) but I wonder how can I avoid using the quotes and still get the value of the cell.
I tried to use the A1Notation function and it supposedly bring the location (B1) but when added to the function I still get the same error (Range not found).
Below is the function as a reference:
function getHEX(cellReference) {
const getCell = SpreadsheetApp.getActiveSheet().getRange(cellReference.toString()).getBackground();
return getCell;
}

Issue:
Unfortunately, there is no straightforward way to do that since =getHEX(B1) would pass directly the value, and not the actual range that is used in google apps script to get the background.
Simple workaround:
You can use ADDRESS, ROW and COLUMN to get the reference as a string in the google sheets side and pass it as an argument in your custom function so it can be used by the getRange(a1Notation) method.
Solutions:
Solution 1:
Google Apps Script:
function getHEX(cellReference) {
const getCell = SpreadsheetApp.getActiveSheet().getRange(cellReference).getBackground();
return getCell;
}
Google Sheets:
=getHEX(ADDRESS(row(E4),column(E4),4))
to get the background color of cell E4. You can also drag down the formula in this way.
Solution 2:
Use the coordinates directly but structure the function to accept two arguments (x and y).
Google Apps Script:
function getHEX(x,y) {
const getCell = SpreadsheetApp.getActiveSheet().getRange(x,y).getBackground();
return getCell;
}
Google Sheets:
=getHEX(row(E4),column(E4))

Related

How do I get the current cell in a Google Apps Script function?

I have a Google Sheet. In that sheet, I have a readonly cell that calls a custom function called formatCell. In that function, I need to dynamically set the number format. I know I can set the number format using the setNumberFormat function. To demonstrate, here is where I'm at:
function formatCell(p) {
var cell = null; // TODO: Get the cell that calls `formatCell`
if (p === 1) {
cell.setNumberFormat("0.000");
} else if (p === 2) {
cell.setNumberFormat("# ?/?");
}
}
What I don't know is how to get the cell that calls formatCell. I know there is a getCurrentCell function. However, that function gets the cell with the current focus. I need to get the cell that is calling formatCell. How do I do that?
To get the cell containing the formula use SpreadsheetApp.getActiveRange().
Please bear in mind that custom functions can't change cells characteristics, they can only return a value or an array of values.
Reference
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#getActiveRange()
https://developers.google.com/apps-script/guides/sheets/functions

App Script Conditional Formatting to apply on sheet by name

I have been trying to make a Google App Script code which highlight the cell if it has specific text like "L".
I have made a below code but its not working and when i run this no error appears. i do not know what is the problem.
Can you have a look at it, please that why its not working.
function formatting() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Dec');
var range = sheet.getRange("C:AG");
if (range == 'L') {
ss.range.setBackgroundColor('#ea9999');
}
}
Issues with the code:
Three things to mention:
range is a range object, not a string. In the if condition you are comparing an object of type range with an object of type string. You need to use getValue to get the values of the range object and then compare that with the string L.
This code will take a lot of time to complete because you have a large range of cells you want to check but also you are iteratively using GAS API methods. As explained in Best Practices it is way more efficient to use batch operations like getValues,
getBackgrounds and setBackgrounds.
Another improvement you can make is to use getLastRow to restrict the row limit of your range since you are looking for non-empty values. There is no reason for checking empty cells after the last row with content.
Google Apps Script Solution:
function formatting() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Dec');
const range = sheet.getRange("C1:AG"+sheet.getLastRow());
const values = range.getValues();
const bcolors = range.getBackgrounds();
const new_bcolors = values.map((r,i)=>r.map((c,j)=>c=='L'?'#ea9999':bcolors[i][j]))
range.setBackgrounds(new_bcolors)
}
Google Sheets Solution:
Another idea would be to just create a conditional formatting in Google Sheets:
and specify a custom color with your hex code:
JavaScript References:
map
ternary operator

How to call ISOWEEKNUM from JS using Google Sheets

I want to call the google sheets function ISOWEEKNUM from JS in a custom function and can't get it working.
Current code is
function customFun(date) {
return ISOWEEKNUM(date);
}
However that just leads to an error:
ReferenceError: ISOWEEKNUM is not defined
How can I get that working and is there a reference how to call standard functions?
I believe your goal as follows.
You want to retrieve the week number using Google Apps Script.
You want to use the function customFun as the custom function.
For this, how about this answer?
Issue and workaround:
Unfortunately, in the current stage, the built-in functions of Spreadsheet cannot be directly used with Google Apps Script. And also, the custom function cannot put the formula. So in this case, it is required to use the workaround. Here, I would like to propose the following 2 workarounds.
Workaround 1:
In this workaround, when =customFun(date) is put to a cell, it is replaced with =ISOWEEKNUM(date) using the OnEdit event trigger.
Sample script:
In order to use this script, please put =customFun(today()) to a cell. By this, the formula of =customFun(date) is replaced with =ISOWEEKNUM(today()) by the OnEdit event trigger.
function customFun(date) {return ""}
function onEdit(e) {
const range = e.range;
const formula = range.getFormula();
const f = formula.match(/=customFun\(([\S\s\w]+)\)/);
if (f.length == 2) {
range.setFormula(`ISOWEEKNUM(${f[1]})`);
}
}
Workaround 2:
In this workaround, when =customFun(today()) is put to a cell, the week number is calculated by Google Apps Script and the result value is put to the cell.
Sample script:
function customFun(date) {
Date.prototype.getWeek = function() {
var onejan = new Date(this.getFullYear(), 0, 1);
return Math.ceil((((this - onejan) / 86400000) + onejan.getDay() + 1) / 7);
}
return date.getWeek();
}
getWeek() is from https://stackoverflow.com/a/7765814/7108653.
References:
Custom Functions in Google Sheets
Simple Triggers

How do I edit the calling cell of a custom function with google apps script from within the custom function?

After searching through various questions and the documentation I still cannot edit the calling cell of a custom function. According to the docs:
Returns the range of cells that is currently considered active. This
generally means the range that a user has selected in the active
sheet, but in a custom function it refers to the cell being actively
recalculated.
Although this description is for the getActiveRange() function one assumes the getActiveCell() functions in the same way.
I am trying to call a helper function from within my custom function which should return the 'active cell' which, to my knowledge, should be the calling cell of the custom function. Not working code:
// returns the current active (calling) cell for use within custom functions
function callingCell() {
return SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getActiveRange()
}
// change background colour of calling cell
function getInfoFromPublicApi(type) {
... // get prices using UrlFetchApp
callingCell().setBackground('green')
return averagePrice(prices, type)
}
I have also tried using the SpreadsheetApp from within the custom function directly, as well as using:
SpreadsheetApp.getActiveSpreadsheet().getActiveCell()
SpreadsheetApp.getActiveSpeadsheet().getActiveRange()
You can go about it two ways. First, set calling cell as a variable. You cannot chain methods together like you're trying to do in the larger function. Or, you can drop the callingCell() function because the information is handled in the event object of onEdit().
Method 1
// returns the current active (calling) cell for use within custom functions
function callingCell() {
return SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getActiveRange();
}
// change background colour of calling cell
function getInfoFromPublicApi(type) {
var active = callingCell();
... // get prices using UrlFetchApp
active.setBackground('green')
return averagePrice(prices, type)
}
Method 2
function onEdit(e) {
// Not sure what your `type` param is, so you'd need to test for that somehow.
... // get prices using UrlFetchApp
e.getRange().setBackground('green');
...
}

Google Scripts Sheets hide/ unhide

In writing a 'custom function' Google Script for my particular sheet, I simply want to hide a column:
function hideColumn(index) {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get first sheet
var sheet = ss.getSheets()[0];
sheet.hideColumns(index);
}
This code works fine when I run it from within the Script editor but if I try to run it from inside a cell "=hideColumn(2)", I get the following error:
"You do not have permission to call hideColumns (line 48)."
From the same sheet/ script I'm able to run other custom functions such as:
function metersToMiles(meters) {
if (typeof meters != 'number') {
return null;
}
return meters / 1000 * 0.621371;
}
This seems to be some issue with the hideColumns function being run from inside a sheet? (ie. custom function?)
Your script 'hideColumn' is not a custom function, but a 'normal script'. Also it does not return anything (whereas the second function does). Only custom functions can be entered like formulas in the spreadsheet. See here for more info. My advice would be to create an extra menu-item using an onOpen trigger so you can run the function from the (spreadsheet)menu.
Hope that helps ?