The Office JavaScript Object
Model provides the ability for your web application and the Office host
application to interact, and that’s where the creativity and innovation
of your web-based solution can intersect with the creativity and
innovation of the Office user.
You can think of Apps for Office in two ways:
those that will interact with documents (document based) and those that
will interact with mail items (mailbox based). At the time of this
writing, document-based apps include Word, Excel, PowerPoint, and
Project. The xsi:type TaskPaneApp and ContentApp are document-based apps for Office. The mailbox-based app, xsi:type MailApp,
is, of course, associated with the Outlook rich client and companion
Outlook Web App (OWA). Therefore, although the Office JSOM is a unified
object model, due to the differences between the sheer nature of a
document and a mailbox item, you will use different parts of the Office
API depending on which Office applications your app for Office will
target.
Fortunately, you do not need to build the
manifest file and all the constituent parts in a raw text editor for an
app for Office as you did in the previous Try It Out, but you instead
have the power of Visual Studio to make this job much less tedious.
With the Apps for Office tools installed in Visual Studio, the File ⇒
New Project process is a guided experience that automatically generates
an appropriate manifest file for a TaskPaneApp, ContentApp, or MailApp.
You then have an immediate F5, debug runtime experience. Of course, you
can go on to fine-tune and customize the manifest and build out your
app, but Visual Studio provides for you a solid starting point.
Document-based Apps
The Office JSOM provides many
capabilities for document-based apps for Office. With Office JSOM, your
web application can programmatically interact with a selection the user
has made, read or write to your document, react to events as the user
enters a specific location or changes data in the document, save one or
more settings in the document so that they are persisted for the next
time the document is opened, and much more. However, the thing to keep
in mind, especially for those who have written VBA or built add-ins in
the past, is that the Office JSOM is not for automation of the Office
client itself, but for enabling programmatic interaction between the
document and your task pane or content app. Everything you do using the
Office JSOM is focused around the user and the document, and should
enable that experience to be a productivity gain for the user.
The Microsoft.Office.WebExtension
namespace contains the JavaScript objects needed to programmatically
interact with the Office client applications that support Apps for
Office. In code, this namespace is referred to by the alias Office. The Visual Studio app for Office project template includes the Office.js library in the Scripts/Lib folder for the Web project. Figure 1 shows the core objects in the API.
The main objects you will use for document-based apps are Office, .context, and .document. When your App for Office is specific to Microsoft Outlook, then you will use the .mailbox
object to access the APIs specific to programming against the mail
client — but this object is covered in further detail later. If you are
creating Apps for Office specifically for Microsoft Project, you will
use the .project part of the Office API.
To keep this discussion straightforward, for
Microsoft Word and Excel, the document object provides the functional
capabilities needed for document interaction. With this you can read
and write an active selection, bind to named locations in the document,
and react to events at the document or bound-location level. Almost all
methods in the Office JSOM are asynchronous to not tie up the UI as
your method call executes. A typical line of code used to retrieve the
data the user has selected in the document looks like this:
Office.context.document.getSelectedDataAsync(...)
Although not a lot of methods are in the API,
they provide the fundamental building blocks for you to build your
solution — it’s up to your imagination on how you stitch them together
to meet a business need. Let’s now explore what Visual Studio provides
for Apps for Office and explore the API.
TRY IT OUT: Using the Office JSOM for Document-based Apps (Explore Office API.zip)
Here you will get a feel for the
baseline App for Office’s project template that Visual Studio sets up
for you. Then you will add some additional code to explore the API for
Office.
1. Run Visual Studio 2012 as Administrator. Select New Project.
2. In the New
Project dialog, expand the Templates ⇒ Visual C# ⇒ Office/SharePoint ⇒
Apps nodes. Select App for Office 2013 and provide the Name: ExploreOfficeAPI. Click OK.
3. In the
Create App for Office dialog, leave the default Task pane app selected,
but uncheck Project and PowerPoint because you will not be targeting
these Office clients. Click Finish.
Before you press F5, take a quick look at
the boilerplate app and the artifacts in the solution. The solution
contains two projects. The first project, ExploreOfficeAPI, has only the manifest file in it. If you double-click the ExploreOfficeAPI.xml
file you see a nice UI to set the values in the manifest file. You can,
of course, view the raw XML by expanding the node and clicking on the
XML file itself. You will also notice the second project called ExploreOfficeAPIWeb.
This project is a boilerplate “remote web” application in that it must
ultimately be hosted on a remote web server. For the F5 experience, it
runs in IIS Express on the local machine. You can use this web project
to build your web application or you could ultimately replace it with
another one of your own. As you browse through the project you’ll see
that Visual Studio has provided a number of folders with the files
needed to serve as the basis for an app for Office. A discussion about
these various files appears later.
4. Press F5 to start debugging. (Internet Explorer must have script-debugging enabled for the app to run.)
5. By running
the app from Visual Studio, the app is automatically registered with
the Office client it is targeted for and inserted into the client.
Click on any cell in the spreadsheet and click the Set Data button.
6. Click on
any other cell in the spreadsheet and type any text value. Press Enter
so the value saves into the cell. Re-select the cell by clicking on it
and then press the Get Data button. The value of the cell is loaded
into the TaskPaneApp text box.
7. Close the Excel application to stop the debugging session.
8. To explore the API, in the Solution Explorer expand the ExploreOfficeAPIWeb node, expand the Pages node, and click the ExploreOfficeAPI.html file to open it.
9. In the HTML page, locate the entire
<div id="Content"> element and replace it completely with the following code:
<button onclick="writeToDoc()"> Write to Document </button><br/>
<button onclick="readFromSelection()"> Read from Document Selection
</button><br/>
<button onclick="bindToData()"> Bind to User-selected Data </button><br/>
<button onclick="readFromBoundData()"> Read from Bound Data </button><br/>
<button onclick="addAnEvent()"> Add an Event </button><br/>
<span>Show: </span><div id="show"></div>
10. In the Solution Explorer under the Scripts/Office node, open the
ExploreOfficeAPI.js file and replace all the code with the following:
Office.initialize = function (reason) {
$(document).ready(function () {
showResult('Document Ready');
});
};
function writeToDoc() {
Office.context.document.setSelectedDataAsync([["apples"],
["pears"], ["oranges"], ["cherries"]], function (asyncResult) {
if (asyncResult.status === "failed") {
showResult('Error: ' + asyncResult.error.message);
}
});
}
function readFromSelection() {
Office.context.document.getSelectedDataAsync("matrix",
function (asyncResult) {
if (asyncResult.status === "failed") {
showResult('Error: ' + asyncResult.error.message);
}
else {
showResult('Read from Selection: ' + asyncResult.value);
}
});
}
function bindToData() {
Office.context.document.bindings.addFromSelectionAsync("matrix",
{ id: 'fruitBinding' },
function (asyncResult) {
if (asyncResult.status === "failed") {
showResult('Error: ' + asyncResult.error.message);
} else {
showResult('A binding type of ' + asyncResult.value.type
+ ' was added with an id of ' +
asyncResult.value.id);
}
});
}
function readFromBoundData() {
Office.select("bindings#fruitBinding").getDataAsync({
coercionType: "matrix" },
function (asyncResult) {
if (asyncResult.status === "failed") {
showResult('Error: ' + asyncResult.error.message);
} else {
showResult('Value of bound selection: ' + asyncResult.value);
}
});
}
function addAnEvent() {
Office.select("bindings#fruitBinding").addHandlerAsync(
"bindingDataChanged", fruitHandler, function (asyncResult) {
if (asyncResult.status === "failed") {
showResult('Error: ' + asyncResult.error.message);
} else {
showResult('New event handler added for binding.');
}
});
}
function fruitHandler(eventArgs) {
eventArgs.binding.getDataAsync({ coerciontype: "matrix" },
function (asyncResult) {
if (asyncResult.status === "failed") {
showResult('Error: ' + asyncResult.error.message);
} else {
showResult('Show bound data change: ' + asyncResult.value);
}
});
}
function showResult(text) {
document.getElementById('show').innerText = text;
}
11. Press F5.
When the Excel document loads, click each button from top to bottom to
see how the API allows programmatic interaction with the document. Once
you add the event, type inside the bound area and change one of the
fruit entries and press enter. You’ll see the results show in the task
pane with your change. Close Excel.
12. Now to show the benefit of the unified object model across the Office client applications, click on the ExploreOfficeAPI project. In the Properties pane find the Start Action property and set it to Microsoft Word. Press F5.
13. Click down
through the buttons again from top to bottom. After you add the event,
change a value within a cell, but you need to click outside the table
for the event to fire in Word. Close Word.
14. In Visual Studio click open the ExploreOfficeAPI.js if it is not already open.
How It Works
The [YourAppnameHere].js is the JavaScript file that Visual Studio generates specifically for your app. For this Try It Out the name is ExploreOfficeAPI.js.
All the other files in the Scripts folder by default are for reference
purposes so you can readily take advantage of the jQuery and ASP.NET
AJAX libraries. But this specific JavaScript file is where you write
the code for your app.
Looking at the ExploreOfficeAPI.js
file, a document-ready function executes as the initialize process
completes after the app is started. In this function you simply wrote
to the web page indicating that the document is loaded and ready.
Let’s take a look into each of the functions. Notice that the writeToDoc
function just passes in a hard-coded array of string values. This
automatically creates a matrix structure for the data: in this case a
single column with four rows. A matrix is a static two-dimensional
structure of columns and rows. You could have multiple columns in the
matrix by following the pattern such as [["apple", "red"], ["banana", "yellow"]] for two columns and two rows and so on. The Office.context.document.setSelectedDataAsynch method does the work for you to create the matrix within the document at any location where the cursor is located.
The readFromSelection function requires the CoercionType to be passed in to the Office.context.document.getSelectedDataAsynch method. Here you see the first parameter of this method uses matrix because the selected data, in this case it is in a columns and rows form. Other coercion types are Text, which can be a single word or any number of paragraphs, and a Table
data type that is also a two-dimensional array but differs from a
matrix structure in that it supports named columns and rows. It also is
dynamic in that it will grow and shrink as additional rows are added or
deleted. So when a table is bound, the binding automatically adjusts as
the table shrinks or grows. A matrix binding remains static with the
originally set number of columns and rows. Word also supports HTML and Ooxml data types so you can get selected data in HTML or Open XML form.
Any data that the user selects on the
screen can be bound so that you can essentially get a programmatic
handle for it to refer to in your code. In the bindToData function, you called the Office.context.document.bindings.addFromSelectionAsync method and passed in the coercion type of matrix with an id that is your specific name for the binding. To retrieve the contents of the bound data at any time as shown in the readFromBoundData function, you use Office.select where you identify the specific binding by the id you want and the coercion type.
Lastly, you added an event to your
specific binding so that any time data changes within the binding you
can take action upon it. Here again you used Office.select identifying the specific binding you want the bindingDataChanged event to fire on.