googlespreadsheetprogramming sample

Upload: shri-anandseo

Post on 13-Oct-2015

34 views

Category:

Documents


0 download

DESCRIPTION

Googlespreadsheetprogramming

TRANSCRIPT

  • Google SpreadsheetProgrammingUse JavaScript To Build SpreadsheetApplications In The Cloud

    Michael MaguireThis book is for sale athttp://leanpub.com/googlespreadsheetprogramming

    This version was published on 2013-10-03

    This is a Leanpub book. Leanpub empowers authors andpublishers with the Lean Publishing process. LeanPublishing is the act of publishing an in-progress ebookusing lightweight tools and many iterations to get readerfeedback, pivot until you have the right book and buildtraction once you do.

    2013 Michael Maguire

  • Tweet This Book!Please help Michael Maguire by spreading the word aboutthis book on Twitter!The suggested hashtag for this book is#googlespreadsheetprogramming.Find out what other people are saying about the book byclicking on this link to search for this hashtag on Twitter:https://twitter.com/search/#googlespreadsheetprogramming

  • Contents

    Chapter 1: Introduction . . . . . . . . . . . . . . . 11.1 What Is Google Apps Scripting? . . . . . . . 11.2 JavaScript or Google Apps Script? . . . . . . 21.3 Summary Of Topics Covered . . . . . . . . . 31.4 What Is Needed To Use This Book . . . . . . 41.5 Intended Readership . . . . . . . . . . . . . 41.6 Note On Code and Code Examples . . . . . . 51.7 Google Spreadsheet Limitations . . . . . . . 51.8 How To Use This Book . . . . . . . . . . . . 61.9 Structure Of This Book . . . . . . . . . . . . 7

    Chapter 2: Getting Started . . . . . . . . . . . . . 92.1 Introduction . . . . . . . . . . . . . . . . . . 92.2 Google Apps Script Examples . . . . . . . . 92.2 Executing Code One Function At A Time . 122.3 Summary . . . . . . . . . . . . . . . . . . . 14

    Chapter 3: User-Defined Functions . . . . . . . . 163.1 Introduction . . . . . . . . . . . . . . . . . . 163.2 Built-in Versus User-Defined Functions . . . 17

  • CONTENTS

    3.3 Why Write User-Defined Functions . . . . . 183.4 What User-Defined Function Cannot Do . . 183.5 Using User-Defined Functions . . . . . . . . 223.6 Introducing JavaScript Functions . . . . . . . 223.7 User-Defined Functions Versus JavaScript Func-

    tions . . . . . . . . . . . . . . . . . . . . . 273.8 Checking Input And Throwing Errors . . . . 273.9 Encapsulating A Complex Calculation . . . . 283.10 Numeric Calculations . . . . . . . . . . . . 303.11 Date Functions . . . . . . . . . . . . . . . . 353.12 Text Functions . . . . . . . . . . . . . . . . 383.13 Using JavaScript Library Methods . . . . . 413.14 Using A Function Callback . . . . . . . . . 433.15 Extracting Useful Information About The

    Spreadsheet . . . . . . . . . . . . . . . . . 453.16 Using Google Services . . . . . . . . . . . . 473.17 Summary . . . . . . . . . . . . . . . . . . . 51

    Appendix A: Excel VBA And Google Apps ScriptComparison . . . . . . . . . . . . . . . . . . . 53Introduction . . . . . . . . . . . . . . . . . . . . 53Spreadsheets and Sheets . . . . . . . . . . . . . 55Ranges . . . . . . . . . . . . . . . . . . . . . . . 67

  • Chapter 1: Introduction1.1 What Is Google Apps Scripting?

    Google Spreadsheets is one of the core components ofGoogle cloud applications and is available to anyone witha Gmail account. It offers a comprehensive set of standardspreadsheet features via built-in functions. The spreadsheetfiles themselves are stored remotely, are accessible fromweb browsers, and can be shared with others in read-onlyor read-edit modes making them ideal collaborative tools.The Google Spreadsheets application also hosts a program-ming language called Google Apps Script (GAS) that isexecuted, not in the browser but remotely on the Googlecloud. Google define Google Apps Script as follows:Google Apps Script is a JavaScript cloud scripting lan-guage that provides easy ways to automate tasks acrossGoogle products and third party services.Google Apps Script can be used to:

    Write user-defined functions for Google Spreadsheets. Write simple macro type applications. Develop spreadsheet-based applications. Integrate other Google products and services.

  • Chapter 1: Introduction 2

    Develop Graphical User Interfaces (GUIs) that can berun as web applications.

    Interact with cloud-based relational databases viaGoogle JDBC Services.

    In summary, Google Apps Script provides the ability ex-tend and integrate Google services to deliver cloud-basedsoftware solutions.

    1.2 JavaScript or Google AppsScript?

    The emphasis here is on using Google Apps Script toenhance and control Google Spreadsheets. Other Googleservices are discussed in the context of how they can beused with Google Spreadsheets. Since Google Apps Scriptis JavaScript (Google describe it as a sub-set of JavaScript1.8), there will inevitably be discussion of JavaScript as aprogramming language. There is therefore some discussionof JavaScript topics as they relate to the code examplesgiven.Regarding terminology, when discussing a general JavaScriptfeature, the code may be referred to as JavaScript butwhen dealing with a Google App specific example, it maybe referred to as Google Apps Script. The meaning ofwhichever term is used should be clear from the context.For example, the Spreadsheet object is central to Google

  • Chapter 1: Introduction 3

    Spreadsheet programming. It is, however, provided by thehosting environment and is not part of JavaScript itself.This duality of the programming language and the ob-jects provided by the hosting environment is similar toJavaScript running on the web client and the DocumentObject Model (DOM) entities that it manipulates.

    1.3 Summary Of Topics Covered

    User-defined functions. Detailed descriptions of Google App Spreadsheet,Sheet, and Range objects and examples of how tomanipulate them.

    Use of the Google JDBC Service to interact withrelational databases.

    Accessing and manipulating other Google servicesincluding e-mail, Google Documents, etc.

    User-interface construction. Turning spreadsheet applications into web applica-tions.

    Examples and discussion ofmore advanced JavaScriptfeatures such as object-oriented programming andcallbacks. There will be an emphasis on how thesetechniques can be applied to Google Spreadsheetprogramming.

    An appendix showing how to translate commonspreadsheet application tasks from Excel Visual Ba-

  • Chapter 1: Introduction 4

    sic for Applications (VBA) code into Google AppsScript.

    1.4 What Is Needed To Use ThisBook

    A Gmail account. Some programming experience and/or spreadsheetpower user level. The latter being defined as some-onewho uses spreadsheet functions such as IF, VLOOKUP,etc .

    A desire to learn and apply JavaScript.

    1.5 Intended Readership

    Spreadsheet power users with experience in Mi-crosoft Excel or some other spreadsheet application.

    Excel VBAdeveloperswishing to addGoogle Spread-sheet application development to their skills set.

    Anyone wishing to learn Google Apps Scriptingto deliver cloud-based, cross-platform spreadsheetapplications.

    Those for whom the content of this blog is ofinterest.

    http://www.javascript-spreadsheet-programming.com/

  • Chapter 1: Introduction 5

    1.6 Note On Code and CodeExamples

    The emphasis on this book is on practical code examples.Some of the code examples are short and only practical inthe sense that they exemplify a Google Apps Script feature.All the code examples in this book are available on Github.The user name is Rotifer and the file name is simplybook_code.gs. The full URL is here. There is some HTMLand Excel VBA in this file and where present it is enclosedin JavaScript multi-line comment blocks (/* */). The codeexamples have been formatted exactly as they appear inthe book. JavaScript features deemed to be problematic (asdefined in Douglas Crockfords OReilly book JavaScriptThe Good Parts) are generally avoided.

    1.7 Google Spreadsheet Limitations

    According to Google, a Google Spreadsheet cannot ex-ceed 400,000 cells in size and each sheet is limited to256 columns. Although this is small compared to Mi-crosoft Excel, it is adequate for the examples given here.Databases are better suited to large-scale data storage thanspreadsheets and Google Spreadsheets can connect to suchdatabases. The use of Google Spreadsheets as a front-end for a relational database running in the cloud will be

    https://github.com/Rotifer/JavaScript/blob/master/book_code.gs

  • Chapter 1: Introduction 6

    discussed in later chapters.

    1.8 How To Use This Book

    There are a lot of code examples in this book and theseshould be copied and pasted into the Google Apps Scripteditor and then executed. They are generally heavily com-mented with further discussion in the text.

    To get maximum benefit from the codeexamples:

    Read the comments and text discussion. Execute the code. Examine the output (written to the log or a spread-sheet).

    Experiment with the code by changing it to see howthe output is affected.

    Just like learning a human language, reading and studyinggrammar can only get you so far. Proficiency in the lan-guage is only gained by a willingness to speak it, to makemistakes and to learn from these mistakes.The more JavaScript you know, the easier you will findthe content here. JavaScript features are discussed whererelevant in the text but the book aims to teach GoogleApps Script as used by Google Spreadsheets so it is not a

  • Chapter 1: Introduction 7

    JavaScript introduction. See the Useful Resources sectionfor details.

    1.9 Structure Of This Book

    In order to get started chapter 2 introduces Google AppsScript so that you can run simple scripts. Some of theobjects and concepts it uses are not discussed until laterchapters. Chapters 3 to 5 are fundamental to everythingthat follows because they discuss JavaScript functions andthe core Google App Application Programming Interfaces(APIs) needed for Google Spreadsheet programming.User-defined functions (also known as custom spreadsheetfunctions) are discussed in depth in Chapter 3. User-definedfunctions are an important topic in any discussion ofspreadsheet programming. They have an added importancein this context because JavaScript functions, which areso important in JavaScript programming generally, areintroduced here.Chapters 4 and 5 cover the core Google Spreadsheet APIs:

    SpreadsheetApp Spreadsheet Sheet Range

  • Chapter 1: Introduction 8

    There are a lot of code examples in these chapters to getyou up-to-speed with the important techniques needed tomanipulate spreadsheets, sheets and ranges.Chapter 6 uses the Google Jdbc API to interact with acloud instance MySQL database. To follow along with theexamples in this chapter, the reader will need program-matic access to a cloud-basedMySQL instance. The chaptershows how to set up one such an instance using GoogleCloud SQL.Menus, message box and input box dialogs are introducedin chapter 7. More complex user interfaces are introducedusing the UiApp toolset.Manipulation of Google Drive, email and calendars isdiscussed in chapters 8 and 9.The final chapter, chapter 10, introduces Html Service forthe creation of spreadsheet-backed web apps.The first of the two appendices will be of interest to ExcelVBA programmers. It presents Google Apps Script andequivalent VBA code for some common spreadsheet pro-gramming tasks. The final appendix provides informationon additional resources such as books, blogs, and websitesthat I have found useful. It also provides details on howto acquire from Github all the code examples given in thebook.

  • Chapter 2: GettingStarted

    2.1 Introduction

    The best way to learn JavaScript/Google Apps Script is towrite some code. Getting started is very straightforward:All that is needed is a Gmail account and a browser withan Internet connection. To run some example code, firstgo to the Google Drive area and create a spreadsheet. Toview the script editor, select Tools->Script editor fromthe spreadsheet menu bar. The first time you do this in anew spreadsheet file, you will be presented with a pop-upwindow entitled Google Apps Script, just ignore and closeit for now. Give the project a name, any name you like, byhovering over and replacing the text untitled project onthe top left. Delete the code stub entitled myFunction sothat the script editor is now blank. Paste in the examplecode in the following sections and save (save icon or menuaction File->Save).

    2.2 Google Apps Script Examples

    Here are four example functions. When pasted into thescript editor, the code formatting applied by the editor

  • Chapter 2: Getting Started 10

    becomes evident and makes the code easier to read.

    1 function sayHelloBrowser() {2 // Declare a string literal variable.3 var greeting = 'Hello world!';4 // Display a message dialog with the greeting5 //(visible from the containing spreadsheet).6 Browser.msgBox(greeting);7 }89 function helloDocument() {10 var greeting = 'Hello world!';11 // Create DocumentApp instance.12 var doc =13 DocumentApp.create('test_DocumentApp');14 // Write the greeting to a Google document.15 doc.setText(greeting);16 // Close the newly created document17 doc.saveAndClose();18 }1920 function helloLogger() {21 var greeting = 'Hello world!';22 //Write the greeting to a logging window.23 // This is visible from the script editor24 // window menu "View->Logs...".25 Logger.log(greeting);26 }27

  • Chapter 2: Getting Started 11

    2829 function helloSpreadsheet() {30 var greeting = 'Hello world!',31 sheet = SpreadsheetApp.getActiveSheet();32 // Post the greeting variable value to cell A133 // of the active sheet in the containing34 // spreadsheet.35 sheet.getRange('A1').setValue(greeting);36 // Using the LanguageApp write the37 // greeting to cell:38 // A2 in Spanish,39 // cell A3 in German,40 // and cell A4 in French.41 sheet.getRange('A2')42 .setValue(LanguageApp.translate(43 greeting, 'en', 'es'));44 sheet.getRange('A3')45 .setValue(LanguageApp.translate(46 greeting, 'en', 'de'));47 sheet.getRange('A4')48 .setValue(LanguageApp.translate(49 greeting, 'en', 'fr'));50 }

  • Chapter 2: Getting Started 12

    2.2 Executing Code One FunctionAt A Time

    In order to execute code, there must be at least one validfunction in the script editor. After pasting the code above,there are four functions that will each be executed in turn.

    Figure 2-1: Google Apps Script Editor displaying the code and theSelect function drop-down list.

    Select function sayHelloBrowser() from the Select func-tion drop-down list on the script editor toolbar and thenpress the execute icon (to the left of the function list drop-down). Switch to the spreadsheet and you will see a smallwindow with the greeting Hello world. These browserpopup displays are modal meaning that they block allsubsequent code execution until they are closed. For thisreason, their use should be limited. The Logger is generallya better tool for writing and displaying output.

  • Chapter 2: Getting Started 13

    Now select the second function named helloDocument()and execute it. This is a much more interesting examplethan the previous one because it shows how one GoogleApps Script can be used to manipulate other applications.The first time you try to execute it, you will get a messagesaying, Authorization required. Once you authorise it andthen execute, it will create a new Google document andwrite the message to it. This example, though trivial anduseless, does demonstrate how Google App Script codewritten in one application can manipulate other applica-tions. This is a very powerful feature andwill be a recurringtheme of this book.The helloLogger() function, when executed, writes the mes-sage to a logging area that is viewable from the script editormenu View->Logs. It is equivalent to the console.login Firebug and Node.js and is generally more useful thanthe Browser.messageBox method used earlier. It will beused frequently in later code examples.The final function helloSpreadsheet() demonstrates twoimportant aspects of Google Apps Script:Firstly, spreadsheets can be manipulated via the Spread-sheet object (the Google documentation refers to Spread-sheet as a class). It provides a method that returns anobject representing the active sheet and that this returnedobject has a method that returns a range, in this instance asingle cell with the address A2. The returned range objectmethod, setValue(), is then called with a string argumentthat is written to cell A1 of the active sheet. These types

  • Chapter 2: Getting Started 14

    of chained method calls look daunting at first. The methodcall chain described above could be re-written as:

    1 var greeting = 'Hello world!',2 activeSpreadsheet =3 SpreadsheetApp.getActiveSpreadsheet(),4 activeSheet =5 activeSpreadsheet.getActiveSheet(),6 rng = activeSheet.getRange('A1'),7 greeting = 'Hello world!';8 rng.setValue(greeting);

    The code above uses a number of intermediate variablesand may be easier to understand initially but after ex-perience with JavaScript generally, the chained methodcall will start to feel easier and more natural. The objectsreferenced in this example will be discussed in detail inchapters 4 and 5.Secondly, the example code shows how easy it is to callanother service from a Google Apps Script function. Herethe LanguageApp was used to translate a simple textmessage into Spanish, German, and French. This abilityto seamlessly access other Google services is extremelypowerful.

    2.3 Summary

    Anyone with a modern browser, an Internet connec-

  • Chapter 2: Getting Started 15

    tion, and a Gmail account can write useful code inGoogle Apps Script.

    The script editor provides a simple Integrated Devel-opment Environment (IDE) that can display objectproperties; provide code highlighting, and debug-ging.

    To execute code, there must be at least one validfunction in the script editor.

    Google Apps Script developed in Google Spread-sheets can access andmanipulate other Google prod-ucts and services.

  • Chapter 3: User-DefinedFunctions3.1 Introduction

    User-defined functions, also known as custom spreadsheetfunctions, allow spreadsheet users and developers to extendspreadsheet functionality. Since spreadsheets are widelyused in finance, engineering, science, etc. there is a need tooffer customised functionality and user-defined functionsare one of the most common and easiest ways to do this.User-defined functions are a good starting point for learn-ing Google Apps Script for a number of reasons becausethey:

    Extend functionality. Provide practice in JavaScript. Can be learned without having to deal with thecomplexities if the Google Apps APIs.

    Learning Google Apps Script poses two challenges: (1)JavaScript and (2) The Google Apps APIs. Spending sometime on user-defined functions really helps with the firstof these challenges and is good preparation for the secondone.

  • Chapter 3: User-Defined Functions 17

    DefinitionA user-defined function is one that can becalled using the equals (=) sign in a spread-sheet cells and writes its return value to thecell.

    3.2 Built-in Versus User-DefinedFunctions

    Modern spreadsheet applications, includingGoogle Spread-sheets, supply a large number of built-in functions andthey owe much of their utility and widespread usage tothese functions. There is also a high degree of standard-isation between spreadsheet applications with respect tofunction names, arguments, and usage to such a degree thatthey generally work uniformly in Google Spreadsheets,Microsoft Excel, OpenOffice Calc and Gnumeric. GoogleSpreadsheets currently has 316 built-in functions spreadover multiple categories, Google Spreadsheet function list.

    https://support.google.com/drive/bin/static.py?hl=en&topic=25273&page=table.cs

  • Chapter 3: User-Defined Functions 18

    3.3 Why Write User-DefinedFunctions

    Familiarity with built-in spreadsheet functionality shouldbe a prerequisite for writing user-defined functions. Re-implementing a function that already exists shows igno-rance of the application, is a waste of time, and has thepotential to introduce bugs. The two main justifications forwriting user-defined functions are for clarity and to extendfunctionality. User-defined functions can add to clarityby giving a name to complex computations. Spreadsheetpower-users can often ingeniously combine the builtinfunctions to effectively create new ones. The disadvantageof this approach is that the resulting formulas can be verydifficult to read, understand and debug. When such func-tionality is captured in a function, it can be given a name,documented and, tested. Secondly, user-defined functionsallow developers to customise spreadsheet applications byadding functionality for their particular domain.

    3.4 What User-Defined FunctionCannot Do

    The single-most important point about user-defined func-tions is that they cannot be used to alter any properties,such as formats, of the spreadsheet or any of its cells. Theycannot be used to send e-mails and cannot be used to insert

  • Chapter 3: User-Defined Functions 19

    new worksheets. Functions can be used to do these thingsbut they cannot be called as user-defined functions. This isa common area of misunderstanding where users attemptto call functions from the spreadsheet using the equalsoperator (=). This results in an error because the functionis trying to alter some spreadsheet property.User-defined functions should be thought of as mathemati-cal functions that have defined inputs and return an output.Their purpose is their return values not their side effects.Excel VBA makes a distinction between subroutines andfunctions. Subroutines do not return a result and cannotbe called as user-defined functions. Consider the followingfunction that takes a range address argument and sets thefont for the range to bold:

    1 function setRangeFontBold (rangeAddress) {2 var sheet =3 SpreadsheetApp.getActiveSheet();4 sheet.getRange(rangeAddress)5 .setFontWeight('bold');6 }

    The code uses Google Apps objects that have not yet beendiscussed but the idea is simple; Take a range input and setthe font to bold for that range. However, when the functionis called from a spreadsheet, it does not work.

  • Chapter 3: User-Defined Functions 20

    Figure 3-1: Error displayed when calling a function with side effectsfrom a spreadsheet.

    The error shown above refers to permissions but the prob-lem is that the called function is attempting to modify sheetproperties.To prove that the function setRangeFontBold() is valid, hereis a function that prompts for a range address using anBrowser.inputBox dialog. It calls the setRangeFontBold()function passing the given range address as an argument.Note that to see the input dialog, you have to call the func-tion in the script editor and then switch to the spreadsheet.

    1 function call_setCellFontBold () {2 var rangeAddress = Browser.inputBox(3 'Set Range Font Bold',4 'Provide a range address',5 Browser.Buttons.OK_CANCEL);6 if (rangeAddress) {7 setRangeFontBold(rangeAddress);8 }9 }

    Code Notes:

  • Chapter 3: User-Defined Functions 21

    Display an input dialog that prompts for a rangeaddress in A1:B10 format (NOT case-sensitive).

    For a single cell, input, enter just the cell address. If OK is pressed, then call function setRangeFont-Bold().

    Remember that when calling this function, you mustswitch to the spreadsheet view to see the inputdialog!

    When this function is called, the following input dialog isdisplayed in the spreadsheet view:

    Figure 3-2: Browser.inputBox prompting for a range address.

    The Browser.inputBox mechanism for requesting user in-put will be discussed in a later chapter. The important pointis that a function may be valid but, if it has side effects suchas altering range properties, then it cannot be called as auser-defined function.

  • Chapter 3: User-Defined Functions 22

    3.5 Using User-Defined Functions

    User-defined functions can be called exactly like built-inones using the equals (=) operator in a spreadsheet cell.They can take zero or more arguments of different typesand these arguments can be either cell references or literalvalues, just like built-in functions. The user-defined func-tions themselves are written in Google Apps Script that,as stated earlier, is JavaScript. To understand and writeuser-defined functions in Google Spreadsheets requires anunderstanding of JavaScript functions.

    3.6 Introducing JavaScriptFunctions

    JavaScript functions are immensely powerful and key tomastering the idioms and patterns of the language. Onlythe basics of JavaScript functions are required for thepurposes of this chapter. There are different ways of declar-ing functions and functions can be nested inside otherfunctions to create closures. Functions can be passed asarguments to other functions and they can be the returnvalues of functions. Functions passed around in this waycan be used as callbacks. These features add great powerbut also complexity. An example using a callback is givenlater in this chapter.For the purposes of this chapter here are the principal points

  • Chapter 3: User-Defined Functions 23

    of note regarding JavaScript functions:

    A function declaration takes the form:

    1 function functionName(comma-separated2 parameters) {3 statements4 }

    When the function is called, the arguments passedin are assigned to the parameters in the functiondefinition.

    These arguments can then be used within the func-tion body.

    Parameters are always passed by value in JavaScriptbut when reference types, such as arrays, are used,the behaviour can appear pass-by-reference.

    If the number of arguments passed in is less thanthe number of parameters in the function definition,the unassigned parameters are given the value unde-fined.

    Variables declared within the function using the varstatement are local, i.e. scoped to, that function andare not visible outside the function.

    Functions in JavaScript are objects and are equippedwith a number of pre-defined attributes.

  • Chapter 3: User-Defined Functions 24

    Two function attributes are important for this chap-ter. These are the arguments object and the lengthproperty.

    The arguments object is an array-like list that storesall the arguments passed to the function when it iscalled.

    The arguments object is not an array but like theArray type it does have a length property that storesthe number of arguments that were actually givenwhen the function was called and its elements canbe accessed using array-like indexing.

    The length property of the function stores the num-ber of arguments the function expects based on thenumber of parameters in the function definition.

    Since JavaScript functions can accept any number ofarguments of any type regardless of the parameterlist, the arguments.length value can be compared tothe function length property to check if the argumentcount is as expected.

    Functions can have an explicit return statement. If noreturn statement is specified, the function will returnthe value undefined.

    User-defined functions without a return statementare pointless.

    A return statement on its own can be used to exit thefunction and will return undefined, again, not muchuse in user-defined functions.

    User-defined functions should always return somevalue other than undefined.

  • Chapter 3: User-Defined Functions 25

    The returned value can be a primitive such as astring, Boolean, or a number. It can also be a ref-erence type such as a JavaScript object or an array.

    To see some of these points in action, paste the followingcode into the Google Apps Script editor and choose and runthe second function named call_testFunc.

    1 function testFunc(arg1, arg2) {2 var i;3 Logger.log('Number of arguments given: ' +4 arguments.length);5 Logger.log('Number of arguments expected: ' +6 testFunc.length);7 for (i = 0; i< arguments.length; i += 1) {8 Logger.log('The type of argument number ' +9 (i + 1) + ' is ' +10 typeof arguments[i]);11 }12 }

    Code Notes:

    Testing function properties: Determine the number of arguments expected againstthe number of arguments passed in.

    Determine the types of all given arguments using thetypeof operator

  • Chapter 3: User-Defined Functions 26

    1 function call_testFunc() {2 Logger.log('First Invocation:');3 testFunc('arg1', 2);4 Logger.log('Second Invocation:');5 testFunc('arg1', 2, 'arg3', false,6 new Date(), null, undefined);7 }

    Code Notes:

    Call function testFunc() twice with different argu-ment lists.

    To see the logger output select View->Logs fromthe script editor menu!

    The function output demonstrates how JavaScript func-tions can be made more stringent by:

    1. Checking the argument count given when the func-tion is called (arguments.length) against the argu-ment count expected based on the parameter list inthe function definition (the function length prop-erty).

    2. Using the typeof operator to determine the typeof each given argument. The typeof operator canalso be used to identify missing argument valueswhere the missing value will be of type undefined.This check can be used to assign defaults using thestatement if (typeof arg === undefined ) { arg =default; }.

  • Chapter 3: User-Defined Functions 27

    3.7 User-Defined Functions VersusJavaScript Functions

    When user-defined functions are called fromwithin spread-sheet cells, their string arguments must be provided indouble quotes. In JavaScript, either single or double quotescan be used to enclose a string literal but only double quotesare acceptable for string literals in user-defined functions.Single quote usage can lead to puzzling errors so beware!JavaScript function names are case-sensitive, function afunc() { } and function aFunc () { } are two differentfunctions. VBA users, watch out for this gotcha! How-ever, when called from a spreadsheet, the function namesare case-insensitive. The implication of this is to be verycareful when naming functions to be called from a spread-sheet. Camel-casing is the JavaScript standard and is usedthroughout here except when defining testing functionsthat may be given the prefix testing_.

    3.8 Checking Input And ThrowingErrors

    JavaScript functions are flexible and can be called withany number of arguments of any type. These issues shouldnot be ignored when writing user-defined functions. Thenumber and type of all given arguments should be verified.In some instances, arguments may have a valid range and

  • Chapter 3: User-Defined Functions 28

    any arguments outside this range should be rejected. Forexample, for numeric arguments negative values may notbe valid.The code examples here generally implement argumentchecking and raise an error if any argument is invalid. Theyall use the throw statement followed by an object literal -defined by the curly braces- that contains two properties,the error name and an error message. Object literals will bediscussed in detail in later chapters. The effect of throwingthe error object when the functions are called from aspreadsheet will be seen in the examples. As a generalrule, all JavaScript functions should throw an error to thecaller if there is any doubt about the validity of any of thearguments.

    3.9 Encapsulating A ComplexCalculation

    The relative standard deviation (RSD) is frequently usedin statistics to express and compare variability of datasets. It is not provided as a built-in spreadsheet function.The formula to calculate it is simply the sample standarddeviation divided by the sample mean multiplied by 100.Given the following values in cells A1 to A10: 19.81 18.2921.47 22.54 20.17 20.1 17.61 20.91 21.62 19.17 The RSDrounded to two decimal places can be calculated using this

    http://en.wikipedia.org/wiki/Relative_standard_deviation

  • Chapter 3: User-Defined Functions 29

    spreadsheet formula:=ROUND(100*(STDEV(A1:A10)/AVERAGE(A1:A10)),2)The functionality expressed in this spreadsheet formula canbe encapsulated in a user-defined function as follows:

    1 // Given the standard deviation and the mean,2 // return the relative standard deviation.3 function RSD (stdev, mean) {4 if (!(typeof stdev === 'number' &&5 typeof mean === 'number')) {6 throw {'name': 'TypeError',7 'message':8 'Function "RSD()" requires ' +9 'two numeric arguments'};10 }11 return (100 * (stdev/mean)).toFixed(2)*1;12 }

    Code Notes:

    Given the mean and standard deviation, return theRelative Standard Deviation expressed as a percent-age.

    Check that two numeric arguments are provided,otherwise, throw an error.

    Use the toFixed() numeric method to round the resultto two decimal places and multiply the result by 1to convert the string returned by toFixed() back to anumber.

  • Chapter 3: User-Defined Functions 30

    Call example: =RSD(STDEV(A1:A10),AVERAGE(A1:A10))

    The above function can be pasted into the script editorand called as described in the documentation. So whatwas gained by writing a user-defined function when acombination of spreadsheet built-in functions can be usedand the user-defined version still uses the spreadsheetSTDEV and AVERAGE built-ins? Firstly, the calculationnow has a meaningful name. Secondly, there is argumentchecking, an error is thrown if anything other than twonumeric values are passed to it. Lastly, the logic is capturedin one place and is documented. These are all good reasonsto consider replacing complex spreadsheet formulas withuser-defined functions.

    3.10 Numeric Calculations

    The following two examples take a single numeric argu-ment as degrees Centigrade or Fahrenheit and use thatargument to return the temperature in the other scale. Touse, paste the two functions into the Google Apps Scripteditor and then call them by name in a cell in the containingspreadsheet. For example, if cell A1 contains the value 0,then the formula =celsiusToFahrenheit(A1) in cell B1 willreturn the result 32 as expected.

  • Chapter 3: User-Defined Functions 31

    1 // Given a temperature value in Celsius2 // return the temperature in Fahrenheit.3 function celsiusToFahrenheit (celsius) {4 if (typeof celsius !== 'number') {5 throw {6 'name': 'TypeError',7 'message': 'Function requires ' +8 'a single number argument'};9 }10 return ((celsius * 9) / 5) + 32;11 }

    Code Notes:

    Given a temperature in Celsius return its value inFahrenheit.

    Throw an error if the given argument is non-numericor omitted.

    1 // Given a temperature in Fahrenheit,2 // return the temperature in Celsius.3 function fahrenheitToCelsius(fahrenheit) {4 if (typeof fahrenheit !== 'number') {5 throw {6 'name': 'TypeError',7 'message': 'Function requires ' +8 ' a single number argument'};9 }

  • Chapter 3: User-Defined Functions 32

    10 return ( fahrenheit - 32 ) * 5/9;11 }

    Code Notes:

    Given a temperature in Fahrenheit, return its valuein Celsius.

    Throw an error if the given argument is non-numericor omitted.

    The arithmetic is very simple here but the typeof checkis essential in both functions to avoid some erroneousinterpretation of spreadsheet input as will be describedbelow. Here is a screenshot showing some input values andthe outputs after calling these two functions:

    Figure 3-3: Input and output for two user-defined functions cel-siusToFahrenheit() and fahrenheitToCelsius().

  • Chapter 3: User-Defined Functions 33

    Note how the thrown error is reported as a comment incells A5 to A7. Without the typeof check, the date value incell A5 would be interpreted as a number of seconds andwould return an unfeasibly large number. The outcome ofevaluating the cell A7 is even more insidious where theblank is interpreted as zero and the function evaluatesto 32. Indeed, 0 Celsius is equal to 32 Fahrenheit but thisis highly misleading. Remove or comment out the typeofcheck and see the effect! The text value in cell A6 willthrow an error regardless of the typeof check, which is tobe expected. However, the default interpretation of datesas numbers and blank cells as zero is a serious trap forthe unwary. The same problem occurs in Excel VBA andis more difficult to guard against.These two examples of user-defined functions are verysimple but they highlight the need for rigorous checking ofinputs. Verifying that arguments are within a valid rangemay also be required to avoid invalid return values. As anexample, the formula to calculate the area of a circle issimple: * radius2. The following function does this butit also checks that the given argument is both numeric andnot less than zero.

  • Chapter 3: User-Defined Functions 34

    1 // Given the radius, return the2 // area.3 // Throw an error if the radius is4 // negative.5 function areaOfCircle (radius) {6 if (typeof radius !== 'number'){7 throw {8 'name': 'TypeError',9 'message': 'Function requires ' +10 'a single numeric argument'};11 }12 if (radius < 0) {13 throw {14 'name': 'ValueError',15 'message': 'Radius myst ' +16 ' be non-negative'};17 }18 return Math.PI * (radius * radius);19 }

    Code Notes:

    Given a radius, calculate and return the area of acircle.

    Throw a type error if the argument is non-numeric. Since a negative radius value makes no sense, throwa value error if the argument is less than zero.

    The function checks that the given radius is numeric andthat the value is not less than zero. Both checks could

  • Chapter 3: User-Defined Functions 35

    have been performed in a single if statement using the &&(and) operator but performing them separately allowsmorespecific errors to be thrown. This approach helps whenfunctions are part of larger applications.

    3.11 Date Functions

    Date manipulation in spreadsheets can be challenging butuser-defined functions can be used to do date manipula-tions and to encapsulate potentially complex spreadsheetmanipulations. For example, knowing the number of daysin the interval between two dates can be useful. A spread-sheet can actually do that without a user-defined function.Subtracting one date value from another returns the differ-ence in days. To demonstrate this in Google Spreadsheets,enter two date values in the format YYYY-MM-DD in twocells and, in a third cell, subtract one from the other to getthe time interval in days. To get an age in days one couldenter =(TODAY() birth_date). There are a few reasonswhy this could be productively written as user-definedfunction:

    The function has a name and can be documented andtested.

    The input values can be checked and dealt with asappropriate.

    The user-defined function can be re-used both inother Google Apps Script functions and more gen-

  • Chapter 3: User-Defined Functions 36

    erally in client-side web applications or in Node.jsscripts.

    Here is a function called intervalInDays() that takes twodate arguments and returns the interval between them indays.

    1 // Given two dates, return the interval in days2 // between them.3 function intervalInDays(date1, date2) {4 var millisecondsPerDay = 86400000;5 if (!(date1 instanceof Date &&6 date2 instanceof Date)) {7 throw {8 'name': 'TypeError',9 'message': 'Function requires ' +10 ' two Date type arguments'};11 }12 return (date1 - date2)/millisecondsPerDay;13 }

    Code Notes:

    Declare a variable containing the number ofmillisec-onds in a day.

    Check that the two given arguments are of typeDate,throw an error if they are not.

    Subtract date2 from date1 to give the millisecondinterval.

  • Chapter 3: User-Defined Functions 37

    Divide by the number of milliseconds in a day to getthe interval in days.

    Return the interval in days.

    1 function test_intervalInDays() {2 var date1 = new Date(),3 date2 = new Date(1972, 7, 17);4 Logger.log(intervalInDays(date1, date2));5 }

    Code Notes:

    Create two date objects, the current date (date1) andan arbitrary date in the past.

    Call function intervalInDays() passing in these twodates as arguments.

    Write the output to the logger. Note: when creating a date object in JavaScript, themonth is zero-based so 7 corresponds to August NOTJuly!

    The code above can be pasted in to the Google Apps Scripteditor. The second function named intervalInDays can becalled from a spreadsheet and returns the interval in daysbetween the first and second date arguments. The typeofoperator is no use this time for type checking becauseit returns the generic object for all non-primitive types

  • Chapter 3: User-Defined Functions 38

    and that includes Date types. The instanceof operator canhowever determine if both arguments are of type Date.Conveniently, Google Apps Script correctly interprets cellinput formatted in the spreadsheet as Date. The testingfunction named test_intervalInDays demonstrates how toconstruct a Date object in JavaScript. The Date object isvery clearly described on the Mozilla Developer Networkwebsite.

    3.12 Text Functions

    Google Spreadsheets text manipulation functions can alsobe complemented and enhanced by writing user-definedfunctions. JavaScript, like most programming languages,refers to the text type as string. Strings in JavaScriptare primitive types but they can be wrapped to behavelike objects. In the context of JavaScript, methods aresimply functions attached to objects. The wrapping of aprimitive so that it becomes an object is known as auto-boxing. Auto-boxing can also be applied to Boolean andNumber primitive types. Since JavaScripts handling ofthis is transparent to the user/programmer, all that reallymatters is that strings have methods that can be used toextract information from them and to generate new strings.Strings can also be manipulated using JavaScript regularexpressions. Regular expressions are very powerful and

    https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date

  • Chapter 3: User-Defined Functions 39

    they are used in some examples in later chapters. Theirspecific use in spreadsheets as user-defined functions arecovered in an entry in the authors blog.To see all the String properties supported by Google AppsScript, paste the following code into the script editor andexecute it. An alphabetical list of string properties is sentto the logger.

    1 // Write String methods to the logger.2 function printStringMethods() {3 var strMethods =4 Object.getOwnPropertyNames(5 String.prototype);6 Logger.log('String has ' +7 strMethods.length +8 ' properties.');9 Logger.log(strMethods.sort().join('\n'));10 }

    The code above uses JavaScripts very powerful introspec-tion capabilities to extract an array of all the propertynames defined for type String on what is known as itsprototype. The logger output shows that there are 39 prop-erties. Most, but not all, of the properties are methods butthe important length property, for example, is not. Theexamples given here are meant to be short and illustrative.

    http://www.javascript-spreadsheet-programming.com/2013/09/regular-expressions.html

  • Chapter 3: User-Defined Functions 40

    As an example, here is a function that returns its stringargument with the characters reversed.

    1 // Reverse the alphabet.2 function test_reverseString () {3 var str = 'abcdefghijklmnopqrstuvwxyz';4 Logger.log(reverseString(str));5 }6 // Return a string with the characters7 // of the input string reversed.8 function reverseString (str) {9 var strReversed = '',10 lastCharIndex = str.length - 1,11 i;12 if (typeof str !== 'string') {13 throw {14 'name': 'TypeError',15 'message': 'Function requires a ' +16 ' single string argument.'};17 }18 for (i = lastCharIndex; i >= 0; i -= 1) {19 strReversed += str[i];20 }21 return strReversed;22 }

    Code Notes:

    Function test_reverseString is called to test reverseS-tring() in Script editor.

  • Chapter 3: User-Defined Functions 41

    Function reverseString() accepts a single string argu-ment and returns a string where the characters are inreverse order.

    It checks that the given argument is a string, if notan exception is thrown.

    Note on variable initialisation: Variable strReversedmust be set to an empty string, otherwise undefinedis prepended to the returned string.

    The example function uses a JavaScript for loop to extractthe string characters in reverse order and appends them toa new string that is built within the loop. The newly builtstring is returned upon completion of the loop. This func-tion highlights the importance of initialising the returnedvariable to an empty string. If this is not done, the variableis initially assigned undefined and when the first stringconcatenation operation takes place, the string representa-tion of undefined, which is undefined, is prepended to thereturned value.

    3.13 Using JavaScript LibraryMethods

    Checking both the number of arguments provided and theirtypes are necessary steps in developing robust and reli-able user-defined functions. JavaScript provides additionalfunctionality that can be used in user-defined functions.For example, the JavaScript Math library is available in

  • Chapter 3: User-Defined Functions 42

    Google Apps Script and provides some useful methods.Simulation of a die throw can be easily implemented usingits methods:

    1 // Return a integer between2 // 1 and 6 inclusive.3 function throwDie () {4 return 1 + Math.floor(Math.random() * 6);5 }

    Code Notes:

    Simulate a die throw by returning a random numberbetween and including 1 and 6.

    Call: =throwDie()

    This function requires no inputs so there is no argumentchecking code. It uses two methods defined in the standardJavaScript Math library to simulate dice throwing. TheMath round() method could also be used here but, as isvery well described here , it leads to biased results. Thisbecomes apparent when the function is called hundreds oftimes. The important point to note is the need for testingand reading of documentation to avoid inadvertent errorsand biases.

    http://www.the-art-of-web.com/javascript/random/#.UPU8tKHC-nY

  • Chapter 3: User-Defined Functions 43

    3.14 Using A Function Callback

    The object nature of JavaScript functions allows them to bepassed as arguments to other functions and, furthermore,to be returned by other functions. The following exampleprovides a taste of the power and flexibility that derivesfrom the fact that functions are objects. It also shows howeasy it is to use a range of cells as an argument. The functionconcatenates an input range of cells using a delimiterargument. There is an in-built Google Spreadsheet functioncalled JOIN that performs this task but the user-definedversion below has one additional feature: It provides anoption to enclose each individual element in single quotes.Here is the code:

    1 // Concatenate cell values from2 // an input range.3 // Single quotes around concatenated4 // elements are optional.5 function concatRng(inputFromRng, concatStr,6 addSingleQuotes) {7 var cellValues;8 if (addSingleQuotes) {9 cellValues =10 inputFromRng.map(11 function (element) {12 return "'" + element + "'";13 });14 return cellValues.join(concatStr);

  • Chapter 3: User-Defined Functions 44

    15 }16 return inputFromRng.join(concatStr);17 }

    An example of a call to this function in the spreadsheetis =concatRng(A1:A5, , true). This returns output likeA,B,C,D,E. There are two interesting aspects to thiscode:

    1. The range input is converted to a JavaScript array.In order to work correctly, all the input must befrom the same column. If the input range is two-dimensional or frommultiple cells in the same row, itwill generate a JavaScript array-of-arrays. That pointis ignored here, but try giving it a two-dimensionalrange input or something like A1:C1 and observethe output!

    2. The more interesting point is the use of the arraymap() method. This method iterates the array andapplies its function argument to each element ofthe array and returns a new array. The functionused here is an anonymous function. It takes oneargument, the array element, and returns it enclosedin single quotes. The anonymous function operatesas a callback. More examples of callbacks will begiven in later chapters. This example just hints at thepower of this approach.

    A version of this function was written in Excel VBA as aquick way of generating input for the IN clause in SQL.

  • Chapter 3: User-Defined Functions 45

    Lists of string values (VARCHARs in database terminology)would be provided in spreadsheets so an Excel user-definedfunction was written to allow the lists to be concatenatedin comma-separated strings with the constituent valuesenclosed in single quotes. There are better ways of runningsuch queries that will be discussed in the JDBC chapter butthis is an approach that can be useful.It is worth noting that built-in Google Spreadsheets canbe combined to get the same output: =CONCATENATE(,JOIN(,, A1:A5), )However, no introduction to JavaScriptfunctions would be complete without at least a brief men-tion of anonymous functions and callbacks.

    3.15 Extracting Useful InformationAbout The Spreadsheet

    All the user-defined functions discussed up to this pointwere written in host-independent JavaScript. They shouldall work in modern browsers or in Node.js scripts. The re-strictions on the actions of user-defined functions were alsodiscussed. However, useful information about a spread-sheet can be returned to spreadsheet cells by means ofuser-defined functions. The examples given below are allfunctions that take no arguments and return some usefulinformation about the active spreadsheet. All can be calledas user-defined functions:

  • Chapter 3: User-Defined Functions 46

    1 function spreadsheetId() {2 return SpreadsheetApp3 .getActiveSpreadsheet().getId();4 }56 function spreadsheetUrl() {7 return SpreadsheetApp8 .getActiveSpreadsheet().getUrl();9 }1011 function spreadsheetOwner() {12 return SpreadsheetApp13 .getActiveSpreadsheet().getOwner();14 }1516 function spreadsheetViewers() {17 var ss =18 SpreadsheetApp.getActiveSpreadsheet();19 return ss.getViewers().join(', ');20 }2122 function spreadsheetLocale() {23 var ss = SpreadsheetApp.getActiveSpreadsheet();24 return ss.getSpreadsheetLocale();25 }

    These examples use Google Apps Script host objects andmethods. The objects in the code examples are discussedextensively in the following two chapters, so read ahead if

  • Chapter 3: User-Defined Functions 47

    you wish to understand them right now. The purpose hereis to just show how user-defined functions can be utilised toextract information about a spreadsheet using host objectmethods.All the functions given above can extract the requiredinformation and return it in a single statement. The func-tions spreadsheetViewers() and spreadsheetLocale() use avariable to reference the active spreadsheet and the valuereturned using a method call to the variable. The reason fordoing this here was simply to make the code more readableby avoiding a wrapped line in the book text.To see these functions in action, just paste the code aboveinto any Google Spreadsheet Script Editor and then in-voke each of them from the spreadsheet using the usualsyntax, example: =spreadsheetId(). All of the examplesexcept spreadsheetViewers() use a Spreadsheet method thatreturns a primitive JavaScript value, namely a string. ThegetUsers() method however returns an array and the func-tion uses the Array type join() method to convert the arrayto a string. The join() call could be omitted and the functionwould still work. However, each user would be written to aseparate cell. To experiment, remove the join() and call thefunction.

    3.16 Using Google Services

    Some of the Google Services can be used in user-definedfunctions. The following examples are taken from two such

  • Chapter 3: User-Defined Functions 48

    services: Google Finance and Google Language.

    3.16.1 Financial Services

    The FinancialApp object provides share price informationon companies quoted on the New York Stock Exchange. ItsgetStockInfo() method takes a stock symbol as an argumentand returns a JavaScript object. The following functionprintFinanceAppKeys() can be invoked from the ScriptEditor and writes its output to the log (Script Editor menu:View->Logs->).

    1 // Print stockInfo object property2 // names to the logger.3 function printFinanceAppKeys() {4 stockSymbol = 'GOOG';5 Logger.log(Object.keys(6 FinanceApp.getStockInfo(7 stockSymbol))8 .sort()9 .join('\n'));10 }

    For now just focus on the output in the log. The workingsof the code will be explained in a later chapter. The codeextracts the array of key names from the object returnedby the getStockInfo() method using a valid stock symbolas an argument, sorts them alphabetically, and then joinsthem all together with new lines. Two of the keys shown

  • Chapter 3: User-Defined Functions 49

    above are used in the following user-defined functions toextract information of interest.

    1 // Given a stock symbol, return the2 // stock price (NYSE).3 function getStockPrice(stockSymbol) {4 return FinanceApp5 .getStockInfo(stockSymbol)['price'];6 }7 // Given a stock symbol, return the8 // full stock name.9 function getStockName(stockSymbol) {10 return FinanceApp11 .getStockInfo(stockSymbol)['name'];12 }

    Example invocations of each: =getStockPrice(GOOG)and =getStockName(GOOG).These two functions each use a key from the object re-turned by the method getStockInfo() and return the valueit maps to. Try experimenting with other keys to see theoutput. If you are interested in big American IT companies,try GOOG, MSFT, AAPL, IBM or ORCL. Thecompanies that these stock symbols refer to are easilyguessed.

  • Chapter 3: User-Defined Functions 50

    3.16.2 Language Services

    User-defined functions can be used as a sort of dictionary totranslate word and phrases. The following three functionscan all be called from the spreadsheet to perform trans-lations from English to three other major West Europeanlanguages.

    1 function translateEnglishToGerman(input) {2 return LanguageApp3 .translate(input, 'en', 'de');4 }56 function translateEnglishToFrench(input) {7 return LanguageApp8 .translate(input, 'en', 'fr');9 }1011 function translateEnglishToSpanish(input) {12 return LanguageApp13 .translate(input, 'en', 'es');14 }

    Example invocation: =translateEnglishToFrench(Try clos-ing the file!) The output: Essayez de fermer le fichier!These functions appear to work well for single words andstraight-forward, non-idiomatic, phrases. However, only afluent speaker could comment on the translation quality.A good check is to re-translate back into the original

  • Chapter 3: User-Defined Functions 51

    and see if it makes sense. I have tried some idiomaticinput such as JavaScript rocks! and JavaScript sucks!- translated into standard English as JavaScript is reallygreat and JavaScript is very bad!- and the translations,unsurprisingly, missed the point.

    3.17 Summary

    Google Spreadsheets provides a large number ofbuilt-in functions.

    User-defined functions can be written to comple-ment these functions and to provide new function-ality.

    Before writing a user-defined function, ensure thatGoogle Spreadsheets does not already provide anequivalent.

    User-defined functions cannot be used to set cellproperties or display dialogs.

    User-defined functions are written in the GoogleApps Scripting version of JavaScript.

    JavaScript functions are very powerful and veryflexible.

    User-defined functions should be rigorously tested. There should be code to check and verify the numberand type of arguments that are passedwhen the user-defined function is called. The JavaScript typeof andinstanceof operators can be used for these purposes.

  • Chapter 3: User-Defined Functions 52

    A variety of invalid data should be passed as ar-guments to ensure that the user-defined functionperforms as expected by throwing an error.

    Use the throw statement with an object literal con-taining a name and message for the error.

    Ensure that the user-defined function deals appro-priately with blank cells.

    Ensure that user-defined functions expecting nu-meric arguments do not misinterpret date input.

    Watch out for implicit JavaScript or spreadsheet typeconversions.

    When using JavaScript built-in functions or methodsprovided by the Math library for example, readthe documentation and test function output againstexpected results to avoid errors and biases.

    The object nature of JavaScript functions allowsthem to be used as callbacks.

    Useful information about a Google Spreadsheet doc-ument can be retrieved with user-defined functionsthat call methods of the SpreadsheetApp class.

    User-defined functions can be used to query Googleservices such as FinancialApp and LanguageApp inorder to return useful information to a spreadsheet.

  • Appendix A: Excel VBAAnd Google Apps Script

    ComparisonIntroduction

    Microsoft Excel remains the dominant spreadsheet ap-plication so many of those coming to Google Apps Scriptprogramming will be very familiar with it. It hosts a pro-gramming language called Visual Basic for Applications(VBA) that can be used to extend functionality, build userinterfaces, integrate with other Microsoft Office appli-cations, and as a front end to relational databases. Thisappendix aims to provide a quick reference for Excel VBAprogrammers by giving some VBA examples in parallelwith equivalent Google Apps Script (basically JavaScript)code for some common spreadsheet programming tasks.VBA and Google Apps Script are very different languagesand the APIs they each use for spreadsheet programminghave been developed independently so their respectivemethods and properties also differ. Despite these differ-ences, the objectives of both languages and the tasks theyare applied to are similar to the extent that an experiencedVBA programmer should be able to pick up Google Apps

  • Appendix A: Excel VBA And Google Apps Script Comparison 54

    Script quite quickly. This appendix assumes knowledge ofVBA and aims to facilitate the readers transition to theGoogle Apps Script environment.The examples below are given in pairs: First the VBAcode and then the functionally equivalent Google AppsScript version with some explanatory comments. The VBAis generally not commented because the examples assumeVBA expertise. Comments are added, however, for trickierand longer examples or when the code examples in thetwo languages are very different due to inherent VBA/-JavaScript differences or divergent API approaches. Thecode examples should perform as described but in manyinstances alternative approaches can be used and the ex-amples may not be optimal.The VBA examples given generally write their output tothe Immediate Window while the Google Apps Scriptequivalents write to the Logger. Some examples write toor format spreadsheet cells.

    Google Apps Script Or JavaScriptJavaScript is used here to refer to generalJavaScript concepts such as arrays.Google Apps Script refers to the specific Googleimplementation as it applies to spreadsheetprogramming and Google App Script APIs.The context should make the usage clear.

  • Appendix A: Excel VBA And Google Apps Script Comparison 55

    Spreadsheets and Sheets

    Spreadsheets and sheets are handled similarly. One differ-ence of note is that Google Apps Script does not make adistinction between Sheets and Worksheets as VBA does.

    Active Spreadsheet

    Multiple spreadsheet files can be open at a given time butonly one is active.

    VBA

    1 Public Sub SpreadsheetInstance(()2 Dim ss As Workbook3 Set ss = Application.ActiveWorkbook4 Debug.Print ss.Name5 End Sub

    Google Apps Script

    1 function spreadsheetInstance() {2 var ss = SpreadsheetApp.getActiveSpreadsheet();3 Logger.log(ss.getName());4 }

    VBA uses the Name property while Google Apps Scriptuses the method getName() to return the value.

  • Appendix A: Excel VBA And Google Apps Script Comparison 56

    Sheet/Worksheet

    Spreadsheets contain sheets. In VBA these are stored ascollections and in Google Apps Script as JavaScript arraysof Sheet objects. The pairs of examples given here call someSheet methods and print the output.

    VBA

    1 Public Sub FirstSheetInfo()2 Dim sh1 As Worksheet3 Set sh1 = ActiveWorkbook.Worksheets(1)4 Dim usedRng As Range5 Set usedRng = sh1.UsedRange6 Debug.Print sh1.Name7 Debug.Print usedRng.Address8 End Sub

    Google Apps Script

  • Appendix A: Excel VBA And Google Apps Script Comparison 57

    1 function firstSheetInfo() {2 var ss = SpreadsheetApp.getActiveSpreadsheet(),3 sheets = ss.getSheets(),4 // getSheets() returns an array5 // JavaScript arrays are always zero-based6 sh1 = sheets[0];7 Logger.log(sh1.getName());8 // getDataRange is analagous to UsedRange9 //in VBA10 // getA1Notation() is functional equivalent to11 // Address in VBA12 Logger.log(sh1.getDataRange().getA1Notation());13 }

    Sheet Collections

    The previous examples extracted a single Sheet object andcalled some of its methods. The example pairs here loopover the all the sheets of the active spreadsheet and printthe sheet names.

    VBA

  • Appendix A: Excel VBA And Google Apps Script Comparison 58

    1 Public Sub PrintSheetNames()2 Dim sheets As Worksheets3 Dim sheet As Worksheet4 For Each sheet In ActiveWorkbook.Sheets5 Debug.Print sheet.Name6 Next sheet7 End Sub

    Google Apps Script

    1 // Print the names of all sheets in the active2 // spreadsheet.3 function printSheetNames() {4 var ss = SpreadsheetApp.getActiveSpreadsheet(),5 sheets = ss.getSheets(),6 i;7 for (i = 0; i < sheets.length; i += 1) {8 Logger.log(sheets[i].getName());9 }10 }

    Adding And Removing Sheets

    Spreadsheet applications may need to add new sheets to anexisting spreadsheet file and then, after some processing,they may need to then remove one or more sheets. Bothtasks are easily achieved in both VBA and and Google AppsScript.

  • Appendix A: Excel VBA And Google Apps Script Comparison 59

    VBA

    1 ' Add a new sheet to a workbook.2 ' Call the Add method of the3 ' Worksheets collection4 ' Assign a name to the returned5 ' Worksheet instance6 ' Name property.7 Sub AddNewSheet()8 Dim newSheet As Worksheet9 Set newSheet = ActiveWorkbook.Worksheets.Add10 newSheet.Name = "AddedSheet"11 MsgBox "New Sheet Added!"12 End Sub1314 ' Delete a named sheet from the15 ' active spreadsheet.16 ' The sheet to delete is identified17 ' in the Worksheets collection18 ' by name. The returned instance19 ' is deleted by calling its20 ' Delete method.21 ' MS Excel will prompt to confirm.22 Sub RemoveSheet()23 Dim sheetToRemove As Worksheet24 Set sheetToRemove = _25 ActiveWorkbook.Worksheets("AddedSheet")26 sheetToRemove.Delete27 MsgBox "Sheet Deleted!"

  • Appendix A: Excel VBA And Google Apps Script Comparison 60

    28 End Sub

    Google Apps Script

    1 // Add a new sheet to the active spreadsheet.2 // Get an instance of the active spreadsheet.3 // Call its insertSheet method.4 // Call the setName method of the5 // returned instance.6 function addNewSheet() {7 var ss =8 SpreadsheetApp.getActiveSpreadsheet(),9 newSheet;10 newSheet = ss.insertSheet();11 newSheet.setName("AddedSheet");12 Browser.msgBox("New Sheet Added!");13 }1415 // Remove a named sheet from the16 // active spreadsheet.17 // Get an instance of the active18 // spreadsheet.19 // Get an instance of the sheet to remove.20 // Activate the sheet to remove21 // Call the spreadsheet instance method22 // deleteActiveSheet.23 function removeSheet() {24 var ss =25 SpreadsheetApp.getActiveSpreadsheet(),26 sheetToRemove =

  • Appendix A: Excel VBA And Google Apps Script Comparison 61

    27 ss.getSheetByName("AddedSheet");28 sheetToRemove.activate();29 ss.deleteActiveSheet();30 Browser.msgBox("SheetDeleted!");31 }

    The code comments in both languages should adequatelydescribe the actions and objects required to add and removesheets from both spreadsheet applications. The GoogleApps Script mechanism appears a little more complicatedthan its VBA equivalent. In order to remove a sheet, itfirst has to be activated so that the Spreadsheet instancemethod deleteActiveSheet() can be called. Otherwise, bothlanguages work quite similarly.

    Hiding And Unhiding Sheets

    Hiding sheets can help to keep a spreadsheet unclutteredand easy to use while also helping to prevent inadvertentchanges to important data. Lists of values that the appli-cation uses may not be important to the users so they canbe hidden from their view while still remaining availableto the application code. The VBA and Google Apps Scriptcode required to do the hiding, unhiding and listing ofhidden sheets is very similar.Hiding a sheet identified by name.

    VBA

  • Appendix A: Excel VBA And Google Apps Script Comparison 62

    1 Public Sub SheetHide()2 Dim sh As Worksheet3 Set sh = Worksheets.Item("ToHide")4 sh.Visible = False5 End Sub

    Google Apps Script

    1 // Hide a sheet specified by its name.2 function sheetHide() {3 var ss =4 SpreadsheetApp.getActiveSpreadsheet(),5 sh = ss.getSheetByName('ToHide');6 sh.hideSheet()7 }

    Listing hidden sheets

    VBA

  • Appendix A: Excel VBA And Google Apps Script Comparison 63

    1 Public Sub ListHiddenSheetNames()2 Dim sheet As Worksheet3 For Each sheet In Worksheets4 If sheet.Visible = False Then5 Debug.Print sheet.Name6 End If7 Next sheet8 End Sub

    Google Apps Script

    1 // Write a list of hidden sheet names to log.2 function listHiddenSheetNames() {3 var ss =4 SpreadsheetApp.getActiveSpreadsheet(),5 sheets = ss.getSheets();6 sheets.forEach(7 function (sheet) {8 if (sheet.isSheetHidden()) {9 Logger.log(sheet.getName());10 }11 });12 }

    Unhiding hidden sheets

    VBA

  • Appendix A: Excel VBA And Google Apps Script Comparison 64

    1 Public Sub SheetsUnhide()2 Dim sheet As Worksheet3 For Each sheet In Worksheets4 If sheet.Visible = False Then5 sheet.Visible = True6 End If7 Next sheet8 End Sub

    Google Apps Script

    1 // Unhide all hidden sheets.2 function sheetsUnhide() {3 var ss =4 SpreadsheetApp.getActiveSpreadsheet(),5 sheets = ss.getSheets();6 sheets.forEach(7 function (sheet) {8 if (sheet.isSheetHidden()) {9 sheet.showSheet();10 }11 });12 }

    The main difference in the approach taken by each lan-guage in these examples is how they iterate over theWork-sheets collection in VBA and the array of Sheet objects inGoogle Apps Script. Newer versions of JavaScript, includ-ing Google Apps Script, have added some very powerful

  • Appendix A: Excel VBA And Google Apps Script Comparison 65

    methods to arrays. Included in these are methods that takea callback function as an argument that is invoked for eachelement in the array. The forEach() method above is anexample. It operates in a similar manner to the VBA ForEach loop but unlike it, forEach() needs a function as anargument. In the examples above anonymous functionswere used. This type of approach where functions takeother functions as arguments is very powerful but may beunfamiliar to VBA programmers.

    Protecting Sheets

    Hiding sheets provides a type of security through obscu-rity but does not prevent deliberate tampering. Both VBAand Google Apps Script allow you to protect individualworksheets within a spreadsheet but they take very ap-proaches to this.

    VBA

  • Appendix A: Excel VBA And Google Apps Script Comparison 66

    1 ' Password-protect rotect a sheet identified2 ' by name3 Public Sub SheetProtect()4 Dim sh As Worksheet5 Dim pwd As String: pwd = "secret"6 Set sh = Worksheets.Item("ToProtect")7 sh.Protect pwd8 End Sub

    Google Apps Script

    1 // Identify a sheet by name to protect2 // When this code runs, the lock icon3 // will appear on the sheet name.4 // Share the spreadsheet with another user5 // as an editor. That user can edit all6 // sheets except the protected one. The user7 // can still edit the protected sheet.8 function sheetProtect() {9 var ss =10 SpreadsheetApp.getActiveSpreadsheet(),11 sh = ss.getSheetByName('ToProtect'),12 permissions = sh.getSheetProtection();13 ss.addEditor();14 permissions.setProtected(true);15 sh.setSheetProtection(permissions);16 }

    In VBA, a password is set and the protected is using theWorksheet Protect method passing it the password string

  • Appendix A: Excel VBA And Google Apps Script Comparison 67

    as an argument. Once protected even the spreadsheet fileowner needs to know the password to do anything to thesheet. Google Apps Script takes a different approach. Bydefault, only the file creator can see or edit the spreadsheet.The owner can then add editors or viewers to the spread-sheet. A viewer can see all the sheets but not edit themwhile the editor can, as the name suggests, edit the sheetcontents. However, a single sheet can be protected so thatit can be viewed by a user granted editor privilege but isnot editable by them. The code example given above showshow this can be done. Unlike in VBA, however, the ownerof the spreadsheet will always have full edit permissionson all sheets. In other words, the owner cannot removepermissions from themselves.

    Ranges

    Spreadsheet programming is largely about manipulatingranges so this is a long section.

    Selection

    Requiring a user to select an input range is a commonfeature of spreadsheet applications. In order to process theselected cells, the application needs to determine:

    The sheet containing the selection

  • Appendix A: Excel VBA And Google Apps Script Comparison 68

    The location of the selection within the sheet asgiven by its address

    The dimensions of the selection, that is the numberof rows and columns in the selection

    This information is extracted and printed in the followingexamples

    VBA

    1 Public Sub PrintSelectionDetails()2 Debug.Print "Selected Range Details: "3 Debug.Print "-- Sheet: " & _4 Selection.Worksheet.Name5 Debug.Print "-- Address: " & _6 Selection.Address7 Debug.Print "-- Row Count: " & _8 Selection.Rows.Count9 Debug.Print "'-- Column Count: " & _10 Selection.Columns.Count11 End Sub

    Google Apps Script

  • Appendix A: Excel VBA And Google Apps Script Comparison 69

    1 // Prints details about selected range in2 // active spreadsheet3 // To run, paste code into script editor,4 // select some cells on any sheet,5 // execute code and6 // check log to see details7 // Prints details about selected range8 // in active spreadsheet9 // To run, paste code into script editor,10 // select some cells on any sheet,11 // execute code and12 // check log to see details13 function printSelectionDetails() {14 var ss =15 SpreadsheetApp.getActiveSpreadsheet(),16 selectedRng = ss.getActiveRange();17 Logger.log('Selected Range Details:');18 Logger.log('-- Sheet: '19 + selectedRng20 .getSheet()21 .getSheetName());22 Logger.log('-- Address: '23 + selectedRng.getA1Notation());24 Logger.log('-- Row Count: '25 + ((selectedRng.getLastRow() + 1)26 - selectedRng.getRow()));27 Logger.log('-- Column Count: '28 + ((selectedRng.getLastColumn() + 1)29 - selectedRng.getColumn()));

  • Appendix A: Excel VBA And Google Apps Script Comparison 70

    30 }

    VBA provides the handy Selection object which is of typeRange and its methods can be used to extract the re-quired information. The Google Apps Script Spreadsheetobject provides the getActiveSelection() method to returnthe Google Spreadsheets equivalent to the VBA Selection.Its getRow() and getColumn() methods return the rownumber of the first row and first column, respectively, forthe Range object on which they are invoked. The purposeof the getLastRow() and getLastColumn() Range methodsis clear from their names. By using a combination ofthese methods the VBA Selection.Rows.Count and Selec-tion.Columns.Count properties can be mimicked as wasdone above.

    Used Range

    To retrieve the very useful equivalent of the VBA Use-dRange object in Google Apps Script, use the Sheet get-DataRange() method. In both languages it is easy to trans-fer the cell contents of a range into an array. JavaScript ar-rays are a lot more flexible than those in VBA and they arealways zero-based. JavaScripts dynamic typing also makesmatters more straightforward. VBA is a typed languagebut its Variant type negates the all the type-checking.However, it has to be used to receive the Range valueproperty. Another fundamental language difference is thatJavaScript does not distinguish functions and subroutines.

  • Appendix A: Excel VBA And Google Apps Script Comparison 71

    Instead functions are always used and if there is no explicitreturn statement, undefined is the return value.

    VBA

    1 Public Function GetUsedRangeAsArray(sheetName _2 As String) As Variant3 Dim sh As Worksheet4 Set sh = _5 ActiveWorkbook.Worksheets(sheetName)6 GetUsedRangeAsArray = sh.UsedRange.value7 End Function8 Sub test_GetUsedRangeAsArray()9 Dim sheetName As String10 Dim rngValues11 Dim firstRow As Variant12 sheetName = "Sheet1"13 rngValues = GetUsedRangeAsArray(sheetName)14 Debug.Print rngValues(1, 1)15 Debug.Print UBound(rngValues)16 Debug.Print UBound(rngValues, 2)17 End Sub

    Google Apps Script

  • Appendix A: Excel VBA And Google Apps Script Comparison 72

    1 function getUsedRangeAsArray(sheetName) {2 var ss =3 SpreadsheetApp.getActiveSpreadsheet(),4 sh = ss.getSheetByName(sheetName);5 // The getValues() method of the6 // Range object returns an array of arrays7 return sh.getDataRange().getValues();8 }9 // JavaScript does not distinguish between10 // subroutines and functions.11 // When the return statement is omitted,12 // functions return undefined.13 function test_getUsedRangeAsArray() {14 var ss = SpreadsheetApp.getActiveSpreadsheet(),15 sheetName = 'Sheet1',16 rngValues = getUsedRangeAsArray(sheetName);17 // Print the number of rows in the range18 // The toString() call to suppress the19 // decimal point so20 // that, for example, 10.0, is reported as 1021 Logger.log((rngValues.length).toString());22 // Print the number of columns23 // The column count will be the same24 // for all rows so only need the first row25 Logger.log((rngValues[0].length).toString());26 // Print the value in the first cell27 Logger.log(rngValues[0][0]);28 }

  • Appendix A: Excel VBA And Google Apps Script Comparison 73

    Add Colours To Range In First Sheet

    Cells and their contents can be programmatically format-ted just as easily in Google Spreadsheets as in Excel.

    VBA

    1 Sub AddColorsToRange()2 Dim sh1 As Worksheet3 Dim addr As String: addr = "A4:B10"4 Set sh1 = ActiveWorkbook.Worksheets(1)5 sh1.Range(addr).Interior.ColorIndex = 36 sh1.Range(addr).Font.ColorIndex = 107 End Sub

    Google Apps Script

    1 // Select a block of cells in the first sheet.2 // Use Range methods to set both the font and3 // background colors.4 function addColorsToRange() {5 var ss =6 SpreadsheetApp.getActiveSpreadsheet(),7 sheets = ss.getSheets(),8 sh1 = sheets[0],9 addr = 'A4:B10',10 rng;11 // getRange is overloaded. This method can12 // also accept row and column integers13 rng = sh1.getRange(addr);

  • Appendix A: Excel VBA And Google Apps Script Comparison 74

    14 rng.setFontColor('green');15 rng.setBackgroundColor('red');16 }

    Range Offsets

    The offset Range property in VBA is implemented inGoogle Apps Script as the Range offset() method. In itsbasic form, the Google Apps Script version can be usedto exactly mimic its VBA namesake as the following codedemonstrates.

    VBA

    1 Public Sub OffsetDemo()2 Dim sh As Worksheet3 Dim cell As Range4 Set sh = _5 ActiveWorkbook.Worksheets(1)6 Set cell = sh.Range("B2")7 cell.value = "Middle"8 cell.Offset(-1, -1).value = "Top Left"9 cell.Offset(0, -1).value = "Left"10 cell.Offset(1, -1).value = "Bottom Left"11 cell.Offset(-1, 0).value = "Top"12 cell.Offset(1, 0).value = "Bottom"13 cell.Offset(-1, 1).value = "Top Right"14 cell.Offset(0, 1).value = "Right"15 cell.Offset(1, 1).value = "Bottom Right"

  • Appendix A: Excel VBA And Google Apps Script Comparison 75

    16 End Sub

    Google Apps Script

    1 // The Spreadsheet method getSheets() returns2 // an array.3 // The code "ss.getSheets()[0]"4 // returns the first sheet and is equivalent to5 // "ActiveWorkbook.Worksheets(1)" in VBA.6 // Note that the VBA version is 1-based!7 function offsetDemo() {8 var ss =9 SpreadsheetApp.getActiveSpreadsheet(),10 sh = ss.getSheets()[0],11 cell = sh.getRange('B2');12 cell.setValue('Middle');13 cell.offset(-1,-1).setValue('Top Left');14 cell.offset(0, -1).setValue('Left');15 cell.offset(1, -1).setValue('Bottom Left');16 cell.offset(-1, 0).setValue('Top');17 cell.offset(1, 0).setValue('Bottom');18 cell.offset(-1, 1).setValue('Top Right');19 cell.offset(0, 1).setValue('Right');20 cell.offset(1, 1).setValue('Bottom Right');21 }

    Pasting and executing these code snippets in either spread-sheet application writes the location of cell B2s neighboursrelative to its location. The Google Apps Script offset()

  • Appendix A: Excel VBA And Google Apps Script Comparison 76

    method is, however, overloaded. This concept was dis-cussed in chapter 5 in relation to the Sheet getRange()method but it merits re-visiting here to show how the func-tionality of its overloaded versions can be implemented inVBA.

    VBA

    1 ' Mimicking Google Apps Script2 ' offset() method overloads.3 Public Sub OffsetOverloadDemo()4 Dim sh As Worksheet5 Dim cell As Range6 Dim offsetRng2 As Range7 Dim offsetRng3 As Range8 Set sh = ActiveWorkbook.Worksheets(1)9 Set cell = sh.Range("A1")10 'Offset returns a Range so Offset11 ' can be called again12 ' on the returned Range from13 ' first Offset call.14 Set offsetRng2 = Range(cell.Offset(1, 4), _15 cell.Offset(1, 4).Offset(1, 0\16 ))17 Set offsetRng3 = Range(cell.Offset(10, 4), _18 cell.Offset(10, 4).Offset(3, \19 4))20 Debug.Print offsetRng2.Address21 Debug.Print offsetRng3.Address

  • Appendix A: Excel VBA And Google Apps Script Comparison 77

    22 End Sub

    Google Apps Script

    1 // Demonstrating overloaded versions of offset()2 // Output:3 // Address of offset() overload 24 // (rowOffset, columnOffset, numRows) is: E2:E35 // Address of offset() overload 3 (rowOffset,6 // columnOffset, numRows, numColumns)7 // is: E11:I148 function offsetOverloadDemo() {9 var ss =10 SpreadsheetApp.getActiveSpreadsheet(),11 sh = ss.getSheets()[0],12 cell = sh.getRange('A1'),13 offsetRng2 = cell.offset(1, 4, 2),14 offsetRng3 = cell.offset(10, 4, 4, 5);15 Logger.log('Address of offset() overload 2 ' +16 '(rowOffset, columnOffset, numRows) is:\17 '18 + offsetRng2.getA1Notation());19 Logger.log('Address of offset() overload 3 ' +20 '(rowOffset, columnOffset, numRows, ' +21 'numColumns) is: '22 + offsetRng3.getA1Notation());23 }

    While the VBA version defines the same ranges as theGoogle Apps Script version, it is not exactly clear. The

  • Appendix A: Excel VBA And Google Apps Script Comparison 78

    key point to realise is that the VBA Range Offset propertyreturns another Range so there is no reason why Offsetcannot be invoked again on this returned Range. However,code like this VBA example should be avoided wherepossible and, if it cannot be avoided, it had better be wellcommented and documented! It was given here purely fordemonstration purposes.

    Named Ranges

    The advantages of using named ranges were outlined inchapter 5. Google Apps Script provides Spreadsheet meth-ods for setting named ranges and for retrieving the Rangeobjects that the names refer to, see chapter 5 for a fulldiscussion. However, there does not appear to be a way toimplement the following VBA functionality.

    VBA

    1 Public Sub PrintRangeNames()2 Dim namedRng As Name3 For Each namedRng In ActiveWorkbook.Names4 Debug.Print "The name of the range is: " & _5 namedRng.Name & _6 " It refers to this address: " & _7 namedRng.RefersTo8 Next namedRng9 End Sub

  • Appendix A: Excel VBA And Google Apps Script Comparison 79

    This VBA code prints details for all named ranges in theactive Excel file. This functionality can be very useful butat the time of writing, I was unable to duplicate it in GoogleApps Script.

    Cell Comments

    Cell comments are a good way to document spreadsheetsand add useful metadata that can describe the meaningof cell contents. They are also amenable to programmaticmanipulation.The Google Apps Script equivalent to Excel commentsare notes. These are Range attributes that can be set andretrieved with with the Range getters and setters setNote()and getNote(), respectively.

    Cell CommentsComments in Google Spreadsheets set fromthe spreadsheet are not the same as notes setprogrammatically. There does not appearto be a way to programmatically manipu-late comments set from the spreadsheet byusers.

    Setting Cell Comments

    VBA

  • Appendix A: Excel VBA And Google Apps Script Comparison 80

    1 Public Sub SetCellComment(sheetName As String, _2 cellAddress As String, _3 cellComment As String)4 Dim sh As Worksheet5 Dim cell As Range6 Set sh = ActiveWorkbook.Worksheets(sheetName)7 Set cell = sh.Range(cellAddress)8 cell.AddComment cellComment9 End Sub10 Public Sub test_SetCellComment()11 Dim sheetName As String12 sheetName = "Sheet1"13 Dim cellAddress As String14 cellAddress = "C10"15 Dim cellComment As String16 cellComment = "Comment added: " & Now()17 Call SetCellComment(sheetName, _18 cellAddress, _19 cellComment)20 End Sub

    Google Apps Script

  • Appendix A: Excel VBA And Google Apps Script Comparison 81

    1 function setCellComment(sheetName, cellAddress,2 cellComment) {3 var ss =4 SpreadsheetApp.getActiveSpreadsheet(),5 sh = ss.getSheetByName(sheetName),6 cell = sh.getRange(cellAddress);7 cell.setNote(cellComment);8 }9 function test_setCellComment() {10 var sheetName = 'Sheet1',11 cellAddress = 'C10',12 cellComment = 'Comment added ' + Date();13 setCellComment(sheetName, cellAddress, cellCom\14 ment);15 }

    Removing Cell Comments

    VBA

  • Appendix A: Excel VBA And Google Apps Script Comparison 82

    1 ' Need to check if the cell has a comment.2 ' If it does not, then exit the sub but if3 ' it does, then remove it.4 Public Sub RemoveCellComment(sheetName _5 As String, _6 cellAddress As String)7 Dim sh As Worksheet8 Dim cell As Range9 Set sh = ActiveWorkbook.Worksheets(sheetName)10 Set cell = sh.Range(cellAddress)11 If cell.Comment Is Nothing Then12 Exit Sub13 Else14 cell.Comment.Delete15 End If16 End Sub17 Public Sub test_RemoveCellComment()18 Dim sheetName As String19 sheetName = "Sheet1"20 Dim cellAddress As String21 cellAddress = "C10"22 Call RemoveCellComment(sheetName, _23 cellAddress)24 End Sub

    Google Apps Script

  • Appendix A: Excel VBA And Google Apps Script Comparison 83

    1 // To remove a comment, just pass an empty string2 // to the setNote() method.3 function removeCellComment(sheetName, cellAddres\4 s) {5 var ss =6 SpreadsheetApp.getActiveSpreadsheet(),7 sh = ss.getSheetByName(sheetName),8 cell = sh.getRange(cellAddress);9 cell.setNote('');10 }11 function test_removeCellComment() {12 var sheetName = 'Sheet1',13 cellAddress = 'C10';14 removeCellComment(sheetName, cellAddress);15 }

    Selectively Copy Rows From One Sheet ToA New Sheet

    Copying rows from one sheet to another based on somepre-determined criterion is a common spreadsheet task.Given the input in the figure below, the code examplesgiven do the following:

    Insert a new sheet named Target into which rowswill be copied

    Copy the header row to the new sheet Check each of the data rows and if the secondcolumn value is less than or equal to 10000 then copy

  • Appendix A: Excel VBA And Google Apps Script Comparison 84

    the row to the new sheet.

    Figure Appendix A.1: Data input sheet

    VBA

    1 ' This VBA code is commented because the2 ' VBA approach differs3 ' considerably from the Google Apps Script one.4 ' Note: the Offset() method of the Range5 ' object uses 0-based indexes.6 Public Sub copyRowsToNewSheet()7 Dim sourceSheet As Worksheet8 Dim newSheet As Worksheet9 Dim newSheetName As String10 newSheetName = "Target"11 Dim sourceRng As Range12 Dim sourceRows As Variant13 Dim i As Long

  • Appendix A: Excel VBA And Google Apps Script Comparison 85

    14 Set sourceSheet = _15 Application.Worksheets("Source")16 Set newSheet = ActiveWorkbook.Worksheets.Add17 newSheet.Name = newSheetName18 ' Use a named range as marker19 ' for row copying (VBA hack!)20 newSheet.Range("A1").Name = "nextRow"21 Set sourceRng = sourceSheet.UsedRange22 ' Copy the header row23 sourceRng.Rows(1).Copy Range("nextRow")24 ' Moved the named range marker down one row25 Range("nextRow").Offset(1, 0).Name = _26 "nextRow"27 'Skip header row by setting i,28 ' the row counter, = 229 ' i starts at 2 to skip header row30 For i = 2 To sourceRng.Rows.Count31 If sourceRng.Cells(i, 2).value _32

  • Appendix A: Excel VBA And Google Apps Script Comparison 86

    43 Next i44 End Sub

    Google Apps Script

    1 // Longer example2 // Copy rows from one sheet named "Source" to3 // a newly inserted4 // one based on a criterion check of second5 // column.6 // Copy the header row to the new sheet.7 // If Salary

  • Appendix A: Excel VBA And Google Apps Script Comparison 87

    Figure Appendix A.1: Data output sheet

    The Google Apps Script Sheet appendRow() is very conve-nient and significantly simplifies the code when comparedto the VBA example. Taking an array of values, it just addsa row to the sheet that contains these values. In VBA therange name next is used as a marker for the destinationto where the selected row is copied. After each copyingoperation, it has to be moved down by one row to be readyfor the next row to copy.

    Print Addresses And Formulas For Range

    The code examples below demonstrate how to loop over arange of cells one cell at a time.

    VBA

  • Appendix A: Excel VBA And Google Apps Script Comparison 88

    1 Public Sub test_PrintSheetFormulas()2 Dim sheetName As String3 sheetName = "Formulas"4 Call PrintSheetFormulas(sheetName)5 End Sub6 Public Sub PrintSheetFormulas(sheetName _7 As String)8 Dim sourceSheet As Worksheet9 Dim usedRng As Range10 Dim i As Long11 Dim j As Long12 Dim cellAddr As String13 Dim cellFormula As String14 Set sourceSheet = _15 ActiveWorkbook.Worksheets(sheetName)16 Set usedRng = sourceSheet.UsedRange17 For i = 1 To usedRng.Rows.Count18 For j = 1 To usedRng.Columns.Count19 cellAddr = _20 usedRng.Cells(i, j).Address21 cellFormula = _22 usedRng.Cells(i, j).Formula23 If Left(cellFormula, 1) = "=" Then24 Debug.Print cellAddr & _25 ": " & cellFormula26 End If27 Next j28 Next i29 End Sub

  • Appendix A: Excel VBA And Google Apps Script Comparison 89

    Google Apps Script

    1 function test_printSheetFormulas() {2 var sheetName = 'Formulas';3 printSheetFormulas(sheetName);4 }5 function printSheetFormulas(sheetName) {6 var ss =7 SpreadsheetApp.getActiveSpreadsheet(),8 sourceSheet = ss.getSheetByName(sheetName),9 usedRng = sourceSheet.getDataRange(),10 i,11 j,12 cell,13 cellAddr,14 cellFormula;15 for (i = 1; i

  • Appendix A: Excel VBA And Google Apps Script Comparison 90

    28 }

    The Google Apps Script Range getCell() method is anal-ogous to the VBA Range Cells property. Both expect twointeger arguments for the row and column indexes andboth are one-based.

    Table of ContentsChapter 1: Introduction1.1 What Is Google Apps Scripting?1.2 JavaScript or Google Apps Script?1.3 Summary Of Topics Covered1.4 What Is Needed To Use This Book1.5 Intended Readership1.6 Note On Code and Code Examples1.7 Google Spreadsheet Limitations1.8 How To Use This Book1.9 Structure Of This Book

    Chapter 2: Getting Started2.1 Introduction2.2 Google Apps Script Examples2.2 Executing Code One Function At A Time2.3 Summary

    Chapter 3: User-Defined Functions3.1 Introduction3.2 Built-in Versus User-Defined Functions3.3 Why Write User-Defined Functions3.4 What User-Defined Function Cannot Do3.5 Using User-Defined Functions3.6 Introducing JavaScript Functions3.7 User-Defined Functions Versus JavaScript Functions3.8 Checking Input And Throwing Errors3.9 Encapsulating A Complex Calculation3.10 Numeric Calculat