19

When I call a spreadsheet function, say int(f2), the function operates on the value in the cell. If cell("F2") contains 3.14159, the result would be 3. But when I call a different type of function — for example: row(f8) — the function takes the cell reference, and not the value, in this case, returning 8.

How do I get my custom function to work with the reference, rather than the value?

I can pass a string, and use getRange(), but, if I move or update the cells on the sheet, the strings won't change.

Really simple example:

function GetFormula(cellname) {
  return SpreadsheetApp.getActiveSheet().getRange(cellname).getFormula();
}

With this in my sheet's code, I can retrieve the formula in C4 like this: =GetFormula("C4")

But, this argument is a string, and I would rather pass a cell reference. A somewhat more complicated issue requires the calling cells to update when copied and pasted.

Any ideas?

Community
  • 1
  • 1
HardScale
  • 971
  • 1
  • 7
  • 18
  • 1
    Here is a workaround and not a solution - `=GetFormula(ADDRESS(ROW(F8), COLUMN(F8)))` – megabyte1024 Aug 31 '12 at 05:57
  • 1
    That will do what I want, but, boy, is it ugly! Now, I have to explain it to anyone who sees it, ya know? – HardScale Sep 06 '12 at 19:22
  • Related thread on [webapps.se]: [How to pass a range into a custom function in Google Spreadsheets?](http://webapps.stackexchange.com/questions/10629/how-to-pass-a-range-into-a-custom-function-in-google-spreadsheets/) – Rubén Jun 08 '16 at 03:39

3 Answers3

13

(From my answer on Web Apps.) One can get a reference to the passed range by parsing the formula in the active cell, which is the cell containing the formula. This makes the assumption that the custom function is used on its own, and not as a part of a more complex expression: e.g., =myfunction(A1:C3), not =sqrt(4+myfunction(A1:C3)).

The method also supports references to other sheets, such as =myfunction(Sheet2!A3:B5) or =myfunction('Another Sheet'!B3:G7).

As a demo, this function returns the first column index of the passed range. This bit is at the very end of the function; most of it deals with range extraction.

function myfunction(reference) {
  var sheet = SpreadsheetApp.getActiveSheet();
  var formula = SpreadsheetApp.getActiveRange().getFormula();
  var args = formula.match(/=\w+\((.*)\)/i)[1].split('!');
  try {
    if (args.length == 1) {
      var range = sheet.getRange(args[0]);
    }
    else {
      sheet = ss.getSheetByName(args[0].replace(/'/g, ''));
      range = sheet.getRange(args[1]);
    }
  }
  catch(e) {
    throw new Error(args.join('!') + ' is not a valid range');
  }

  // everything so far was only range extraction
  // the specific logic of the function begins here

  var firstColumn = range.getColumn();  // or whatever you want to do with the range
  return firstColumn;
}
Community
  • 1
  • 1
2

I was working on this a few months ago and came up with a very simple kludge: create a new sheet with the name of each cell as its contents: Cell A1 could look like:

= arrayformula(cell("address",a1:z500))

EDIT: The above no longer works. My new formula for 'Ref'!A1 is

= ArrayFormula(char(64+column(A1:Z100))&row(A1:Z100))

Name the sheet "Ref". Then when you need a reference to a cell as a string instead of the contents, you use:

= some_new_function('Ref'!C45)

Of course, you'll need to check if the function gets passed a string (one cell) or a 1D or 2D Array. If you get an array, it will have all the cell addresses as strings, but from the first cell and the width and height, you can figure out what you need.

HardScale
  • 971
  • 1
  • 7
  • 18
  • 1
    you can just pass _cell("address",a1:z500)_ to custom function and then that function can retrieve `cell` object reading string argument as a cell address, no need for extra sheet – mvidelgauz Oct 02 '16 at 12:05
  • I noted that in the OP. Strings don't update when the cells get moved around. – HardScale Oct 02 '16 at 12:59
  • Not sure what you mean. I just implemented a function which I call this way: _MyFunc(CELL("address",D17) )_ and it works when I move target cell... – mvidelgauz Oct 02 '16 at 13:20
  • When I use your solution on a multicell array I only get the address of the top left cell, which is why I've updated my answer to include the actual working formula. – HardScale Oct 08 '16 at 16:57
-2

When you pass a range to a custom function the parameter is of type Range, which you can then use the fetch the values, etc.

Edit: This in incorrect.

Eric Koleda
  • 12,420
  • 1
  • 33
  • 51
  • 2
    That's true if I call the function from another function. But, if I use the function in a spreadsheet, the arg is automatically de-referenced into the contents of the cell. If you could give me an example of a spreadsheet formula that calls a custom function and can pass that function a Range, I would be really grateful. – HardScale Sep 06 '12 at 19:18
  • 1
    My apologies, I had misunderstood how the range was passed. You are correct, only the values are passed. – Eric Koleda Sep 07 '12 at 17:52