In trying to learn more about JavaScript (Google Apps Script flavor), I created an object structure that I think might be useful for a number of projects. My main goals for this little demonstration are:
- learn the use objects (classes) and inheritance
- minimize calls to the Spreadsheet Service by summoning a data table once per sheet
- use the Named Ranges on the spreadsheet to access the data in the table
The code below seems successful, but surely can be improved. A couple of major questions are:
- Is there a better way to accomplish the inheritance of methods and properties than this?
- The Spreadsheet() function gets run for each of the Sheet objects, resulting in the environment structure having separate "ss" and "namedRangeList" properties in each of the Sheet objects. Is this normal and expected? Or is there a better approach to avoid this duplication? Or, is JavaScript just recording pointers to a single instance of these objects, so it really doesn't matter that they appear to be duplicated?
- Because they are common to and the same for all of the Sheets, I had expected "ss" and "namedRangeList" to show up only at the Environment level and therefore available to the Sheets through inheritance rather than duplication.
- What other changes or approaches would improve my fledgling use and understanding of classes and objects?
Here is a stripped down version of my code that preserves the essence of the structure but leaves out comments, error handling, and other functionality.
function Environment() {
this.title = 'Car & Driver';
this.ui = SpreadsheetApp.getUi();
this.dd = new Drivers();
this.cc = new Cars();
}
function Spreadsheet() {
this.ss = SpreadsheetApp.getActiveSpreadsheet();
this.namedRangeList = {};
var namedRanges = this.ss.getNamedRanges();
for (var i = 0; i < namedRanges.length; i++) {
var range = namedRanges[i].getRange();
this.namedRangeList[namedRanges[i].getName()] = {
sheet: range.getSheet().getSheetName(),
row: range.getRow(),
column: range.getColumn(),
rowCount: range.getNumRows(),
columnCount: range.getNumColumns(),
}
}
}
Spreadsheet.prototype = Object.create(Environment.prototype);
function Sheet() {
Spreadsheet.call(this);
this.sheet = this.ss.getSheetByName(this.sheetName);
this.data = this.sheet.getDataRange().getValues();
}
Sheet.prototype = Object.create(Spreadsheet.prototype);
function Cars() {
this.sheetName = 'Cars';
this.abbreviation = 'cc';
Sheet.call(this);
}
Cars.prototype = Object.create(Sheet.prototype);
function Drivers() {
this.sheetName = 'Drivers';
this.abbreviation = 'dd';
Sheet.call(this);
}
Drivers.prototype = Object.create(Sheet.prototype);
Sheet.prototype.idxOf = function(namedRange) {
return (this.namedRangeList[namedRange].rowCount == 1) ?
this.namedRangeList[namedRange].row - 1 :
this.namedRangeList[namedRange].column - 1;
}
function test_Environment() {
var env = new Environment();
env.ui.alert('The third driver is ' +
env.dd.data[3][env.dd.idxOf('ddFirst')] + ' ' + env.dd.data[3][env.dd.idxOf('ddLast')] + '.');
var tests = [
['dd', 2, 'ddLast' , 'Bailey' ],
['dd', 3, 'ddLicense' , 'pro' ],
['cc', 1, 'ccRadio' , 122.5 ],
['cc', 4, 'ccModel' , 'Corvette'],
];
tests.forEach(function(t) {
var v = env[t[0]].data[t[1]][env[t[0]].idxOf(t[2])];
Logger.log( (v == t[3]) + ': ' + (t[0] == 'dd' ? 'Driver ' : 'Car ') +
t[1] + ' ' + t[2].slice(2) + ' is ' + v );
});
env.ui.alert(env.title + ' is all done');
}