Scripts, scripts, scripts!

Here is another one that I use all the time as an alternative to ARRAYFORMULA.
The neat thing about this is that it works with any formulas, whereas ARRAYFORMULA has some limitations.

Again, I didn’t write this one myself, and I can’t recall where I got it from (probably Stackoverflow), so I can’t take any credit for it. But I’ve been using it for 3 or 4 years and it’s never failed me.

What it does and how it works is described in the comments.

Summary
/**
 * Copy Formulas Down
 * This script copies functions from a source row (usually the first data row in a spreadsheet) to
 * rows at the end of the sheet, where the colums for these formulas are still empty.
 * It checks row from the bottom upwards, copying formulas into the rows where there are no formulas yet,
 * and stops as soon as it finds a row which has a formula already.
 * When copying formulas, it leaves values in other cells unchanged.
 */

/**
 * Copy formulas from the a source row in a sheet to rows below
 * @param  {Sheet} sheet     	Google Spreadsheet sheet
 * @param  {int} sourceRow 		(optional) 1-based index of source row from which formulas are copied, default: 2
 */
function copyFormulasDown(sheet, sourceRow) {
    if (sourceRow === undefined) {
        sourceRow = 2;
    }
    var formulas = getFormulas_(sheet, sourceRow);
    if (formulas !== {}) {
        var rows = sheet.getDataRange().getFormulas();
        for (var r = rows.length - 1; r >= sourceRow && rows[r].join('') === ''; r--) {
            copyFormulas_(sheet, r, formulas);
        }
    }
}
/**
 * Copy formulas into row r in sheet
 * @param  {Sheet} sheet     	Google Spreadsheet sheet
 * @param  {int} r 				1-based index of row where formulas will be copied
 * @param  {array} formulas 	array of objects with column index and formula string
 */
function copyFormulas_(sheet, r, formulas) {
    for (var i = 0; i < formulas.length; i++) {
        sheet.getRange(r + 1, formulas[i].c + 1).setFormulaR1C1(formulas[i].formula);
    }
}
/**
 * Read formulas from the source row, creating an array of objects
 * Each objects contains the column index and formula string
 * @param  {Sheet} sheet     	Google Spreadsheet sheet
 * @param  {int} r				1-based index of source row
 * @return {array}				array of objects
 */
function getFormulas_(sheet, r) {
    var row = sheet.getRange(r, 1, 1, sheet.getLastColumn()).getFormulasR1C1()[0];
    var formulas = [];
    for (var c = 0; c < row.length; c++) {
        if (row[c] !== '') {
            formulas.push({
                c: c,
                formula: row[c]
            });
        }
    }
    return formulas;
}

Edit: one thing I should point out is that if you’re adding rows then you need to run this every time a new row (or rows) get added. But that’s easy enough with a trigger.

9 Likes