Quantcast
Channel: Category Name
Viewing all articles
Browse latest Browse all 10804

Excel Does JavaScript! A VBA developer’s perspective

$
0
0

Today's post is brought to you by Daniel Ferry. Daniel is a Microsoft Excel MVP.  He runs the Excel Hero blog and the Excel Hero Academy where students learn advanced Excel techniques.  He can be followed @excelhero or you can interact with the Excel Hero LinkedIn Group, where some of the smartest Excel people on the planet hang out.

The Oscars Ballot Predictor is an Excel 2013 template that showcases a new apps for Office technology.  The Oscar Ballot Predictor (OBP) relies on a custom app for Excel that I built specifically for this template. The following screenshot shows the UI for the Oscars Ballot Predictor.

Figure 1. The Oscars Ballot Predictor UI in Excel.

 

The Oscars Ballot Predictor app utilizes JSON from the PredictWise prediction engine data feed.  By the way, PredictWise predicted 19 of the 24 awards for the 2013 Oscars!

Apps for Office can be inserted into Office documents via the ribbon in a similar fashion as a shape or a chart, but at the heart of all apps is a web page, rendered by Internet Explorer. The screenshot that follows shows the Apps for Office button on the Office Ribbon in Excel 2013.

Figure 2. The Apps for Office button on the Ribbon.

This means that an app is in essence a web application composed of HTML, CSS, and JavaScript that runs inside a sandbox based on Internet Explorer that becomes part of the document.  The interesting part is that through the Office.js API (a Microsoft JavaScript library created for apps) an app can interact with its host document in a number of ways enabling a level of dynamism in documents the likes of which were impossible until now.  The Oscars Ballot Predictor is an Excel template and app and so this article will touch on apps for Excel exclusively, but it should be noted that the same Office.js library can be used to develop Apps for other Office products.

The challenge for experienced Excel VBA developers is that VBA is not part of the equation when developing Excel Apps. Simply put, VBA plays no role whatsoever.  An Excel app can be as simple as a static web page.  To offer any interactivity the app will need to include JavaScript and this will require a learning curve for many VBA developers.

I’d like to posit that it is worth the investment for Excel VBA developers to acquire the JS expertise needed to build useful apps for Excel.  The app can respond to changes in the workbook and the workbook can be updated by the app at any time.

However, there are currently some significant limitations on what can be done and my hope is that over time the Office.js API will be expanded and enriched.  For now, here is what can be done from an Excel app:

  • App data can be persisted (saved) in the XML of the workbook as key-value data pairs called settings. These stored data are not visible from the Excel interface but can be read and written at will by the App.
  • Data can be written to and read from the current active cell in the host workbook.
  • The App can create arbitrary bindings to named ranges and Excel Tables. Those bindings can then be used to read and write data to the bound ranges and tables.
  • Certain workbook events can also be established from the JS code and will run JS routines when those events fire. There are currently only four supported workbook events for Excel Apps:
    • The app can respond when the active cell selection changes, either for the host workbook or for cells within a binding. (That’s two separate events).
    • The app can respond when values change within a binding.
    • The app can respond when the persisted settings change.

That’s it. These are the major interactions that are currently supported by Excel Apps. There are a few other capabilities as well like determining that the host application is Excel.  The API provides additional interactions for other Office products; but from a big picture point of view, the above paragraph identifies what interactions can currently be scripted between an app for Excel and its host workbook.  These capabilities are mainly about raw data transfer.  For example there is no facility to apply or read formatting or cell styles or themes, there is no way to create defined names or charts or PivotTables or filters or any of the many common Excel objects or processes.  An app can read and write raw data and sense data and cell-selection changes and that’s about it.  With a little ingenuity, this is enough to create truly amazing workbooks.  For example, the Oscars Ballot Predictor (OBP) workbook uses conditional formatting to highlight the active cell when the active cell is one of the Oscars award category labels.  The conditional formatting uses the current row and column numbers, which are written to a scratch worksheet by the app for Excel every time the active cell selection changes.

The Oscars Ballot Predictor (OBP) uses the capabilities listed in the list above. Rather than moving the JavaScript of the OBP app to a separate file, as is common in web development, I’ve left it in the main HTML file so that it is easy for those interested to study how the OBP app functions.  Simply view the source by choosing the app itself and you will be presented with the full HTML and JavaScript of the OBP app.

One of the most difficult aspects of building a custom app for Excel for seasoned VBA developers will be the asynchronous fashion that the Office.js API presents to us. In VBA, we are accustomed to blocking. In other words, line 2 always executes only after line 1 is finished.  The Office.js API was specifically built to avoid blocking so that web pages and Excel continue to function even when code is running.  The theory behind this is great, but in practice this takes getting used to, as once you make an asynchronous call, there is no longer any guarantee about which line will be executed first!

For example, the OBP App tracks 24 categories of Oscar nominations and so let’s say our app needs to have 24 distinct bindings to named ranges.  While the app for Excel notion of “bindings” is not something that can be created from VBA, if it could be we would code it in the following fashion.

For i = 1 To 24
    CreateBinding NamesOfBindings(i)Next

This is a different programming paradigm for a VBA developer, and understanding the full ramifications takes time.  Of course the API calls allow us to specify a callback function to execute when the asynchronous call finishes.  However, the documentation for the Office.js API is written for those that fully understand JS and not for VBA developers.  As a result, the documentation examples usually include anonymous functions.  Anonymous functions are a powerful JS construct that have no direct analog in VBA and so the VBA developer may be left scratching his head.  One way to visualize an anonymous function is to imagine defining a VBA function within a parameter to another VBA function, without actually ever naming the function (hence the anonymous part) created on the fly.  Of course, this is not possible in VBA, but it is common in JS, and (unfortunately for the VBA developer) the Office.js documentation uses it almost exclusively.

Here is similar JS code from the app for Excel to create the 24 category bindings to the named ranges.

for (var i = 0; i < 24; ++i) {
    Office.context.document.bindings.addFromNamedItemAsync(NamesOfBindings[i], "matrix", function (result) {if (result.status == 'succeeded') {//Success. Do something here that should be done after a
            // successful binding. } else {//Failure. Do something here to handle the binding failure. };
    });
};

Notice that the Office.js API function for adding a binding includes the word “Async” in the name of the function. This is because it is asynchronous.  The first parameter provided is the name of the named range.  The second parameter specifies that the binding type should be of type matrix, essentially a range of cells.  The third provided parameter is an unnamed (anonymous) function… and the entire anonymous function is defined within this third parameter. 

Again, you can never do this in VBA, yet this practice is common in JS.  Here, the anonymous function is the code that will be executed asynchronously once the API finishes attempting to create the binding. What VBA developers should note is that the callback function does not need to be anonymous.  It can be any normal named function in your project, and you would simply provide its name as the third parameter instead of fully defining the function within the parameter. With JS you have the choice to use normal named functions or anonymous functions, but the documentation for the API seems to mostly use the latter.

There is a delay of an unknown amount of time before this callback function is executed.  In fact, it is quite likely that the for-loop will have completed all 24 calls to addFromNamedItemAsync() before any of the anonymous callback functions are executed. So it is imperative that whatever is done within those callback functions must not depend on any other binding having been completed already. Read that again!

I discovered through the development of the OBP App that while the above loop does work, there is an undefined and practical limit to the number of bindings that can reliably be asynchronously created simultaneously in this fashion. 

I discovered through trial and error (it is not mentioned in the documentation) that the above code works well for around ten or less bindings.  Because our loop is requesting 24 bindings, in practice some will error out unexpectedly and randomly. I tried many different techniques to overcome this problem and you will see that the OBP app code includes randomized delays that seem to work. These are hacks.  I discovered after completing the app that a better approach is to attempt to create binding number 2, only after binding number 1 succeeds. 

var i = 0;
AddMatrixBinding(i);function AddMatrixBinding(i) {
    Office.context.document.bindings.addFromNamedItemAsync(
        NamesOfBindings[i],"matrix",function (result) {if (result.status == 'succeeded') {//Success. if (i < 24) {
                    ++i;
                    AddMatrixBinding(i);
                };
            } else {//Failure. Do something here to handle the binding failure. };
        });
};

Now, the 24 nomination category bindings are created in serial fashion, even though they are done asynchronously.  This is a type of recursion where the main function stipulated callback function is calling the main function repeatedly until all bindings are finished. There is a nuanced distinction here that is critically important for the VBA developer to come to grips with in order to succeed with Excel app development.  The same technique can be used to write to ranges and tables through bindings when a batch of bindings needs to be updated.

Again, the full source code for the Oscars Ballot Predictor is available by simply right-clicking on the app in the template. I encourage you to examine how this app works and how it interacts with its host workbook.

I learned a lot about the future of Excel development by creating the Oscars Ballot Predictor App.  HTML, CSS, and JavaScript are mature and obviously very capable platforms.  It is therefore a major benefit to base the new apps for Excel (and Office) on their foundation.  The problem is that most existing Excel VBA developers to not currently have these skill sets. While web developers do, they are not Excel experts. So there are not that many developers in a position to create apps for Excel at the moment.  I hope this situation changes.  Developers will be pleasantly surprised by what Excel is now capable of if they invest in learning these skills.

What are your feelings on this exciting new technology and on the Oscars Ballot Predictor app?


Viewing all articles
Browse latest Browse all 10804

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>