I'm creating a board game and I have decided to choose Google sheets for that purpose. I have reduced my problem to a minimal example consisting of one sheet and one script.
Following points refer to my dice sheet:
DICEFACES
function applied to the ranges E2:I2 and E10:I10.
DICEFACES
is a custom function I have created in Script editor in
file Code.gs
associated with the stylesheet. It returns a matrix of
dice faces corresponding to the dices in the provided range. It's
body is following:
function DICEFACES(unused_ref_to_range_containing_dices)
{
var app = SpreadsheetApp;
var spr = app.getActiveSheet();
// In the end this array will hold the dice faces. For example two
// 1d6 dices would result in [[1,2,3,4,5,6],[1,2,3,4,5,6]].
//
var Dices = [];
// The the formula inside the active cell (i.e. the cell on which
// we are calling this function). This is a string like:
//
// "=DICEFACES(E2:I2)"
//
var active_formula = spr.getActiveRange().getFormula();
// Set item_range to the one pointed to by the formula. This could
// be a range like E2:I2.
//
var item_range = spr.getRange(active_formula.match(/=\w+\((.*)\)/i)[1]);
// Loop over dice cells in the item_range.
//
for (var i = 1; i <= item_range.getNumColumns(); i++)
{
// "=B2", "=B3", ...
//
var dice_formula = item_range.getCell(1, i).getFormula();
// As soon as we encounter an empty formula, we skip (i.e. there are
// no more dices).
//
if (dice_formula == "")
{
break;
}
// A reference to the cell containing the dice image. We don't really
// need the image, the dice faces are of greater importance to us.
//
var dice_cell = spr.getRange(dice_formula.substr(1));
// Move one column to the right prior to the dice_cell and retreive
// the value of the cell. This is a string like "1,2,3,4,5,6".
//
var dice_csv = dice_cell.offset(0, 1).getValue();
// Convert the CSV string to a javascript array like [1,2,3,4,5,6]
// and push it to Dices.
//
Dices.push(dice_csv.split(",").map(Number));
}
return Dices;
}
The problem is that when I change the dice faces in column C, the DICEFACE
formulas are not being recalculated. Just before I had created the screenshot I added ,4
suffix to the cell C2 and as you can see there's no 4
in cell N2. However, if I either re-save theCode.gs
script file or change the dices in E2:I2, the recalculation occurs immediately.
I'm pretty sure I know where the problem is: Because I'm traversing the cells in a script, the sheet app itself does not see a reference linkage between the cells in column C and the formulas in K2 and K10. Looking at my sheet, the cell referencing is probably something like:
K4 <-- E2:I2 <-- B2, B3 (C is not here)
K10 <-- E10:I10 <-- B4, B5 (C is not here)
The meaning of my notation A <-- B
is If there's a change in range B, update cell A
.
What should I change to make the automatic recalculation happen immediately after I modify the dice faces? And if this is not possible, what would be the best approach to accomplish my task?
The problem is that when I change the dice faces in column C, the
DICEFACE
formulas are not being recalculated.
DIFACE is a custom function and custom functions are recalculated when the spreadsheet is opened and custom function arguments values change.
Considering the above, in order to minimize the changes to your custom function add a second argument to work as a trigger.
Change the regular expression
/=\w+\((.*)\)/i
to
/=\w+\((.*),.*\)/i
Then call your custom function in the following way
=DICEFACES(E2:I2,C2)
or
=DICEFACES(E2:I2,C2:C5)
Modified version of the OP custom function
/**
* Returns a matrix of dice faces corresponding to the dices in the provided range.
*
* @param {Array} unused_ref_to_range_containing_dices Reference to range. i.e. E2:I2
* @param {String|Number|Date|Array} ref_as_trigger Reference to a range used as trigger. i.e. C2 or C2:C5
* @return array
* @customfunction
*/
function DICEFACES(unused_ref_to_range_containing_dices,ref_as_trigger)
{
var app = SpreadsheetApp;
var spr = app.getActiveSheet();
// In the end this array will hold the dice faces. For example two
// 1d6 dices would result in [[1,2,3,4,5,6],[1,2,3,4,5,6]].
//
var Dices = [];
// The the formula inside the active cell (i.e. the cell on which
// we are calling this function). This is a string like:
//
// "=DICEFACES(E2:I2)"
//
var active_formula = spr.getActiveRange().getFormula();
// Set item_range to the one pointed to by the formula. This could
// be a range like E2:I2.
//
var item_range = spr.getRange(active_formula.match(/=\w+\((.*),.*\)/i)[1]); // CHANGED
// Loop over dice cells in the item_range.
//
for (var i = 1; i <= item_range.getNumColumns(); i++)
{
// "=B2", "=B3", ...
//
var dice_formula = item_range.getCell(1, i).getFormula();
// As soon as we encounter an empty formula, we skip (i.e. there are
// no more dices).
//
if (dice_formula == "")
{
break;
}
// A reference to the cell containing the dice image. We don't really
// need the image, the dice faces are of greater importance to us.
//
var dice_cell = spr.getRange(dice_formula.substr(1));
// Move one column to the right prior to the dice_cell and retreive
// the value of the cell. This is a string like "1,2,3,4,5,6".
//
var dice_csv = dice_cell.offset(0, 1).getValue();
// Convert the CSV string to a javascript array like [1,2,3,4,5,6]
// and push it to Dices.
//
Dices.push(dice_csv.split(",").map(Number));
}
return Dices;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With