Last active
November 2, 2022 00:20
-
-
Save brainysmurf/b3bf73bf47384635f9d7 to your computer and use it in GitHub Desktop.
Convenient Fill Down On Submit script for Google Sheets with linked Google Form
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
by ClassroomTechTools.com | |
This is free and unencumbered software released into the public domain. | |
Anyone is free to copy, modify, publish, use, compile, sell, or | |
distribute this software, either in source code form or as a compiled | |
binary, for any purpose, commercial or non-commercial, and by any | |
means. | |
INSTRUCTIONS: | |
In a Google Sheet linked with a Google Form: | |
Copy, paste, and save this file into a script file (Tools -> Script Editor) | |
Prepare the data: | |
1) Make a second row below the first (so you basically have two header rows) | |
2) Give new columns a label (content of label name is not significant) | |
3) Define the second row under that new column "FillDown" (exactly that) | |
4) Define the third row (the first row with data) as the formula you desire | |
Prepare the trigger: | |
Set up an on submit trigger to run "fillDownOnSubmit" | |
Go to the form, and add a new response. | |
When you go back to the sheet, you'll see that the data is auto filled down for you. | |
*/ | |
/* | |
Two utility functions that provide for classical classes in js, from http://speakingjs.com/es5/ch17.html | |
*/ | |
function copyOwnPropertiesFrom(target, source) { | |
Object.getOwnPropertyNames(source) // (1) | |
.forEach(function(propKey) { // (2) | |
var desc = Object.getOwnPropertyDescriptor(source, propKey); // (3) | |
Object.defineProperty(target, propKey, desc); // (4) | |
}); | |
return target; | |
}; | |
function subclasses(SubC, SuperC) { | |
var subProto = Object.create(SuperC.prototype); | |
copyOwnPropertiesFrom(subProto, SubC.prototype); | |
SubC.prototype = subProto; | |
SubC._super = SuperC.prototype; | |
}; | |
/* | |
Define an Range 'class' that lets us iterate | |
See which columns are there, etc. | |
*/ | |
function AbstractRange(range, options) { | |
this.options = typeof options !== 'undefined' ? options : {}; | |
this.range = range; | |
this.initSheet(); | |
this.numHeaderRows = this.options.numHeaderRows || this.sheet.getFrozenRows() || this.defaultNumHeaderRows(); | |
this.initHeaders(); | |
this.initValues(); | |
// Store any extra headers in headersExtra and make this.headers correct | |
this.headersExtra = null; | |
if (this.headers.length > 1) this.headersExtra = this.headers.slice(1); | |
this.headers = this.headers[0]; | |
this.initObjects(); | |
// For iteration: | |
this._curRow = 0; | |
this._curCol = 0; | |
} | |
AbstractRange.prototype.defaultNumHeaderRows = function () { | |
return 1; | |
} | |
AbstractRange.prototype.next = function () { | |
var curRow = this._curRow; | |
var curCol = this._curCol; | |
this._curCol += 1; | |
if (this._curCol >= this.values[0].length) { | |
this._curRow += 1; | |
this._curCol = 0; | |
} | |
if (this.values[curRow] && this.values[curRow][curCol]) return this.values[curRow][curCol]; | |
return null; | |
} | |
AbstractRange.prototype.initSheet = function () { | |
this.sheet = this.range.getSheet(); | |
} | |
AbstractRange.prototype.initHeaders = function () { | |
this.headers = this.sheet.getRange(1, this.range.getColumn(), this.numHeaderRows, this.range.getLastColumn()).getValues(); | |
} | |
AbstractRange.prototype.initValues = function () { | |
this.values = this.range.getValues(); | |
} | |
AbstractRange.prototype.initObjects = function () { | |
this.objects = []; | |
this.values.forEach(function (row, rowIndex) { | |
var rangeObject = {}; | |
this.headers.forEach(function (header, headerIndex) { | |
rangeObject[header] = row[headerIndex]; | |
}.bind(this)); | |
this.objects.push(rangeObject); | |
}.bind(this)); | |
} | |
function FillDownOnSubmit(range, options) { | |
FillDownOnSubmit._super.constructor.call(this, range, options); | |
} | |
FillDownOnSubmit.prototype.initHeaders = function () { | |
this.headers = []; | |
} | |
FillDownOnSubmit.prototype.initObjects = function () { | |
this.objects = []; | |
// initial values for looping through headers | |
var lastColumnInRange = this.range.getLastColumn(); | |
var lastColumnInSheet = this.sheet.getLastColumn(); | |
var headers = this.sheet.getRange(1, lastColumnInRange+1, this.numHeaderRows, lastColumnInSheet).getValues(); | |
headers.forEach(function (headerRow, headerRowIndex) { | |
headerRow.forEach(function (header, headerIndex) { | |
if (this.passes(header, headerRowIndex, headerIndex)) { | |
var column = lastColumnInRange + headerIndex + 1; | |
obj = { | |
column: column, | |
source: this.sheet.getRange(this.numHeaderRows+1, column), | |
} | |
this.objects.push(obj); | |
} | |
}.bind(this)); | |
}.bind(this)); | |
} | |
FillDownOnSubmit.prototype.passes = function (header, headerRowIndex, headerIndex) { | |
if (this.options.hasOwnProperty('secondRow')) { | |
return headerRowIndex == 1 && header === this.options.secondRow; | |
} | |
return header !== ''; | |
} | |
FillDownOnSubmit.prototype.fillDown = function () { | |
//this.sheet.setActiveSelection(this.range); // this results in an error on the server | |
this.values.forEach (function (row, rowIndex) { | |
this.objects.forEach(function (obj) { | |
var row = this.range.getRow()+rowIndex; | |
if (row > this.numHeaderRows+1) { | |
var dest = this.sheet.getRange(row, obj.column); | |
obj.source.copyTo(dest); | |
} | |
}.bind(this)); | |
}.bind(this)); | |
} | |
subclasses(FillDownOnSubmit, AbstractRange); | |
function fillDownOnSubmit(e) { | |
(new FillDownOnSubmit(e.range, {secondRow: "FillDown"})).fillDown(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment