February 2013

Volume 28 Number 02

Microsoft Office - Exploring the New JavaScript API for Office

By Stephen Oliver | February 2013

This article is the first in a series of in-depth looks at the JavaScript API for Office, newly introduced in Microsoft Office 2013. It presupposes that you’re familiar with apps for Office. If not, the MSDN documentation page, “Overview of apps for Office” (bit.ly/12nBWHG), provides a broad overview of and general introduction to the API.

This article and the others in this series, while not exhaustive, go deep into the API, touching on key aspects that will give you a solid, richer understanding of how the apps for Office API works.

In this first article, we review the apps for Office object model. Part 2 will focus on the core task of how to access Office file content and will review the event model. Part 3 will consider the concept of data binding and examine the basics of working with custom XML parts. Finally, Part 4 will close the series with a focused look at mail apps.

Throughout this series, we often make reference to the apps for Office API documentation. You can find the official documentation, code samples and community resources at the Apps for Office and SharePoint Developer Center on MSDN (dev.office.com).

Overview of the JavaScript API for Office

The JavaScript API for Office comprises a complete object model. The API is contained within a set of JavaScript files, starting with the office.js file. An app must include a reference to the office.js file to use the JavaScript API for Office. On load, the office.js file loads the other required scripts that it needs to operate, including the scripts needed for the host environment and the locale strings. Fortunately, you can add a reference to the office.js file using a content delivery network (CDN), so you don’t need to deploy a copy of the office.js file along with your app. Here’s an example:

 

<!-- When deploying an app, you should always
  load the CDN version of the office.js file. -->
<script src=
  "https://appsforoffice.microsoft.com/lib/1.0/hosted/office.js">
</script>

The object model was designed around several goals:

  1. “Write once, run everywhere.” It had to be extensible—not tied to a specific host application, but built around capabilities available in multiple host applications. Apps access host-specific functionality in a consistent way.
  2. Cross-platform. Compatibility ranked high on this list, too; thus, the object model isn’t tied to a specific version of Office. As well, the same code works on the Web App versions of the Office client applications, where supported. For example, an app for Excel can work on the Excel Web App just as well as in the Excel client application.
  3. Performance and security. It needed to be maximized for performance, so that apps can be as unobtrusive to users as possible. Also, the JavaScript API was designed to interact directly with document content without having to automate the Office applications, improving the stability and security of the solutions.

Another key goal for the JavaScript API was to attract Web developers to the Office platform. Thus, the object model was built with modern Web programming in mind. You can leverage your current skills and knowledge of other JavaScript libraries, such as jQuery, when creating apps in conjunction with the JavaScript API for Office.

The Asynchronous Programming Pattern

As mentioned, performance was a key goal in the design of the apps for Office API. One of the ways that the designers enhanced the performance of the API was through the heavy use of asynchronous functions.

The use of asynchronous functions avoids blocking an app during execution in the event a function takes a while to return. The asynchronous function is invoked, but program execution doesn’t wait for the function to return. Instead, it continues while the asynchronous function is still executing. This allows the user to continue to use the Office document while the app is potentially still working.

Some key points for understanding the asynchronous design in the apps for Office API covered in this section are:

  • The common signature of asynchronous functions in the apps for Office API
  • The use of optional parameters in asynchronous functions
  • The role of the AsyncResult object in asynchronous functions

We’ll discuss each in turn.

Common Signature of Asynchronous Functions in the Apps for Office API All asynchronous functions in the apps for Office API have the same naming convention and the same basic signature. Every asynchronous function name ends in “Async,” for example, like this: Document.getSelectedDataAsync.

The signature for all asynchronous functions adheres to the following basic pattern:

functionNameAsync(requiredParameters,  [, options], [callback]);

The required parameters are followed by two other parameters: an object that holds optional parameters and a callback function, both of which are always optional.

Optional Parameters in Asynchronous Functions The optional JavaScript object in the signature of asynchronous functions is a collection of key/value pairs, separated by a colon, where the key is the name of the parameter and the value is the data that you want to use for that parameter. The order of the key/value pairs doesn’t matter as long as the parameter name is correct. The MSDN documentation for each asynchronous function details what parameters are available to use in the options object for that particular function.

For example, the Document.setSelectedDataAsync method has the same basic signature common to all asynchronous functions in the apps for Office:

Office.context.document.setSelectedDataAsync(data [, options], callback);

Like all asynchronous functions in the API, Document.set­SelectedDataAsync has an options object that holds optional parameters, but the parameters for its options object are different from those for other asynchronous functions in the API, because the point of this function is to set data. So the optional parameters for Document.setSelectedDataAsync are related to setting data:

  • coercionType: A CoercionType enumeration that specifies the format for the data you insert (text, HTML, OOXML, table or matrix)
  • asyncContext: A user-defined object that’s returned unchanged in the AsyncResult object that’s passed in to the callback function as its only parameter

That same concept applies to all the other asynchronous functions.

You can either supply the object that contains the optional parameters as an object literal inline in the asynchronous function call, or create an object first and then pass that object in for the parameter. Following are two code samples that show both ways of supplying the options object using the Document.setSelectedDataAsync function.

Passing the options parameter inline:

function setData(data) {
  Office.context.document.setSelectedDataAsync(data, {
  coercionType: Office.CoercionType.Text }  
  );
}

Passing the options parameter in a JavaScript object:

function setData(data) {
  var options = { coercionType: Office.CoercionType.Text };
  Office.context.document.setSelectedDataAsync(data, options );
}

The Role of the AsyncResult Object in Asynchronous Functions The third parameter in the common signature for asynchronous functions in the JavaScript API for Office is the optional callback parameter. The callback parameter is exactly as it sounds: a function you provide that’s invoked when the asynchronous operation completes. Of course, you can provide either a named function or an anonymous function inline in the call to the asynchronous function. The key thing to note here is the role of the AsyncResult object with respect to the callback function.

When the runtime invokes your callback, it passes in an Async­Result object as the only argument for the callback. The AsyncResult object contains information about the asynchronous operation, such as: whether or not the operation succeeded; what errors, if any, occurred; and the return value, if any, of the asynchronous function. In fact, in all asynchronous functions that return some kind of data or object, the AsyncResult is the only way you can get at the returned value. You do this using the AsyncResult.value property.

For example, the following code snippet gets the size of the document and displays it in the specified HTML element on the app UI. In order to get the file size, you first get the file object that the Document.getFileAsync method returns through the AsyncResult.value property. Here’s how to do this:

function getFileData(elementId) {
  Office.context.document.getFileAsync(Office.FileType.Text,
  function (asyncResult) {
    if (asyncResult.status === 'succeeded') {
      var myFile = asyncResult.value;
      $(elementId).val(myFile.size);
    }
  });
}

The getFileData function calls the Document.getFileAsync method, specifying that it should return the file content as text. It then uses the value property of the AsyncResult object passed in to the anonymous function callback to get a reference to the File object. Then it displays the size of the file in the specified element using the size property of the File object. In a similar way, you’ll use the AsyncResult.value property to get the return value of any asynchronous function in the apps for Office API. 

You can read more about the Document.getFileAsync method in the next article of this series.

Object Model Hierarchy

The JavaScript API for Office aims to provide compatibility across versions of Office and symmetry across different host applications. To support these goals, the JavaScript API has a lean object model with a distinct hierarchy that isn’t directly tied to any specific host application. Instead, the object model hosts a targeted set of capabilities for interacting with Office documents, scoped to the type of app (task pane, content or mail app) using them.

Figure 1 provides an abbreviated overview of the top-level hierarchy of objects in the JavaScript API for Office (note that the entire object model isn’t shown). Specifically, the diagram demonstrates the relationships between the Office, Context, Document, Settings, Mailbox and RoamingSettings objects.

The Object Model Hierarchy in the JavaScript API for Office
Figure 1 The Object Model Hierarchy in the JavaScript API for Office

Each host application (Word, Excel, Excel Web App, PowerPoint, Project, Outlook and Outlook Web App) can use a subset of the capabilities included in the API. For example, roughly 40 percent of the object model pertains solely to mail apps that can only be used in Outlook and the Outlook Web App. Another portion of the object model allows interaction with Custom XML Parts, which is only available in Word 2013.

Figure 2 shows the capabilities available to specific host applications.

Figure 2 Availability of Capabilities in the JavaScript API for Office by Host Application

Capability Word Excel/Excel Web App PowerPoint Outlook/Outlook Web App Project
Get/set data as text, table, matrix All All Text only   Text only
Settings All All All (RoamingSettings)  
Get file All   Compressed only    
Bindings All All      
Custom XML Parts All        
HTML and OOXML All        
Mailbox       All  

Shared Objects in the Object Model The JavaScript API for Office has a definitive entry point, the Office object, which is available to all types of apps and in all of the host applications. The Office object represents a specific instance of an app inserted into a document, workbook, presentation, project, e-mail message or appointment. It can access bindings between the app and the document using the select method. (We’ll discuss bindings in greater depth in a future article.) Most importantly, the Office object exposes the initialize event for the app, which allows you to build initialization logic for the app (more on that in a future article). Finally, the Office object contains a reference to the Context object for the app.

The Context object, which is also available to all types of apps and in all of the host applications, exposes information about the runtime environment that’s hosting the app. In addition to storing the language settings for the app, the Context object provides the entry point to runtime capabilities in the JavaScript API for Office that are specific to the host in which the app was activated.

For example, you can access the document (Document object) associated with the app through the Context.document property. However, this property returns a value only when called from within a host application that supports it, that is, from within a task pane or content app. If we attempt to access the Context.document property from a mail app, we’ll get an “undefined object” error. Likewise with the Context.mailbox property: In a mail app, it returns the mailbox (Mailbox object) opened in the host application. In a task pane app, it’s undefined.

Support for Task Pane and ContentApps in the Object Model For task pane and content apps, the Document object represents the document, workbook, presentation or project into which the app has been inserted. The Document object provides the highest degree of access to the file’s content—in essence, it’s the primary point of contact between an app and an Office document.

Almost all of the techniques for accessing the content in the Office document require use of the Document object. For this reason, you might want to capture a reference to the Document object when the app initializes as shown in Figure 3.

Figure 3 Storing a Reference to the Document Object When the App Initializes

// Add a handler to the initialize event of the Office object
Office.initialize = function (reason) {
  $(document).ready(function () {
    app.get_Document(Office.context.document);
 
    // Other initialization logic goes here
  })
}
 
// Use a self-executing anonymous function to encapsulate the
// functionality that the app uses
var app = (function () {
 
  var _document;
  function get_Document(officeDocument) {
    _document = officeDocument;
  }
 
  // Other fields and functions associated with the app
 
  return {
    get_Document: get_Document
    // Other exposed members
  };
})()

When an app is activated within a Project file, the Document object exposes additional, specific capabilities targeted for Project files. Through the Document object, an app can get data for specific tasks, views, fields and resources in the project. An app can also add event listeners to monitor when the user changes the selected view, task or resource selected in the project. (We’ll talk more about using the Document object in an app for Project in the next article.)

Also exposed by the Document object is the Settings object, which represents the “property bag” for an app. An app can store and persist custom properties across app sessions in the same document using the Settings object. The properties travel with the document: If you share an Office file that contains an app with someone else, the custom properties stored in the app will be available when the other person reads the file.

Storing and retrieving settings using the property bag is simple. The Settings.set method creates the setting in memory as a key/value pair. To get the properties out of the property bag, we use the Settings.get method, passing in the setting’s name (key), to get the value. Both the set and get methods are synchronous. To store the settings across sessions, we need to call the Settings.saveAsync method, which saves all of the custom properties contained in the app when the document is saved.

The code sample, “Apps for Office: Persist custom settings” (bit.ly/UEiZff), provides additional examples of how to use the Settings object and how to store data in an app.

Support for Mail Apps in the Object Model For mail apps, the Mailbox object provides the entry point of data access for mail-app-specific functionality. As the name implies, the Mailbox object corresponds to the mailbox of the current user and travels to wherever users read their e-mail—either in the Outlook client application or in the Outlook Web App. In addition to providing access to individual e-mail messages and appointments (through the Mailbox.item property), the Mailbox object allows the app to create new appointments, access the profile of the local user and even get the user’s local time.

Like the Document object for content and task pane apps, you might want to capture a reference to the Mailbox object when the app initializes, as shown in Figure 4.

Figure 4 Storing a Reference to the Mailbox Object in a Global Variable When the App Initializes

// Add a handler to the initialize event of the Office object
Office.initialize = function (reason) {
  $(document).ready(function () {
    app.get_Mailbox(Office.context.mailbox);
 
    // Other initialization logic goes here
  })
}
 
// Use a self-executing anonymous function to encapsulate the
// functionality that the app uses
var app = (function () {
 
  var _mailbox;
  function get_Mailbox(mailbox) {
    _mailbox = mailbox;
  }
 
  // Other fields and functions associated with the app
 
  return {
    get_Mailbox: get_Mailbox
    // Other exposed members
  };
})()

The RoamingSettings object, which is also available only in mail apps, is similar to the Settings object for document-centric apps (task pane and content apps). It allows apps to persist custom properties as name/value pairs across sessions. However, unlike the Settings object, which saves the custom properties within the host Office file, the RoamingSettings object saves the custom settings to the current user’s mailbox. This makes the custom properties available to the app no matter what message the user is looking at or how the user has accessed his mailbox (in Outlook or the Outlook Web App).

For more information about the object model hierarchy in the JavaScript API for Office, see the MSDN documentation page, “Understanding the JavaScript API for Office” (bit.ly/UV2POY).

Testing Whether a Capability Can Be Used in a Host Application

As we alluded to earlier, one of the strengths of the JavaScript API for Office is the “develop once, host many places” nature of apps for Office. For example, the same task pane app can be activated within Word, Excel, Project and PowerPoint (provided that its manifest allows all of those capabilities).

Yet, because not all apps have access to the exact same list of capabilities, an app could be inserted into a host application that doesn’t allow the capabilities that the app requires. For example, Project currently doesn’t provide access to the Settings object. An app that tries to access the Settings object when inserted into Project will raise an “undefined object” error.

Thus, developers must include logic in their apps for testing the availability of the capabilities they need. In the example with Project, the best technique for detecting capabilities in a host application is through a simple if block:

// Test for Settings object in host application
if (Office.context.document.settings) {
 
  // Provide implementation that uses the Settings object
 
}
else {
 
  // Use some other technique for saving custom properties,
  // like localStorage, sessionStorage or cookies
 
}

For more information about how to detect whether a member is available in the host application, see the MSDN documentation page, “How to: Determine host application support for specific API members,” at bit.ly/TR5ZlB.

To summarize this article, we’ve discussed the meat and potatoes of the JavaScript API for Office. We described the object model hierarchy at a high level and discussed the asynchronous pattern as it’s implemented in the object model. We also described how to test whether a capability is supported in a host application.

In the next article in this series, we’ll take a closer look at the simplest, yet most powerful ways for working with data in an app for Office. We’ll describe how to get and set selected data in more depth. We’ll look at getting all of the file content and how to parse it. Also, we’ll discuss apps in Project and how to read task, resource and view data. Finally, we’ll review the event model in the JavaScript API for Office: what events you can code against and how to handle the results.

Stephen Oliver* *is a programming writer in the Office Division and a Microsoft Certified Professional Developer (SharePoint 2010). He writes the developer documentation for the Excel Services and Word Automation Services, along with PowerPoint Automation Services developer documentation. He helped curate and design the Excel Mashup site at ExcelMashup.com.

Eric Schmidt* *is a programming writer in the Office Division. He has created several code samples for apps for Office, including the popular “Persist custom settings” code sample. In addition, he has written articles and created videos about other products and technologies within Office programmability.

Thanks to the following technical experts for reviewing this article:Mark Brewster, Shilpa Kothari and Juan Balmori Labra