Passing cell references to spreadsheet functions

HardScale picture HardScale · Aug 31, 2012 · Viewed 14.8k times · Source

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?

Answer

user3717023 picture user3717023 · Jun 22, 2016

(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;
}