This exercise shows you how to build
an integrated solution where the app for SharePoint is
SharePoint-hosted and contains an app-level ECT for its data source and
an app for Office that consumes the external list data using REST.
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 SharePoint 2013 and provide the Name: C13EmpReferralBCSAppForOffice. Click OK.
3. In the New
App for SharePoint dialog, set your Office 365 SharePoint Online
Developer or Enterprise Preview site URL to use for debugging and
choose SharePoint-hosted as the location to host your app for
SharePoint. Click Finish.
4. Right-click the C13EmpReferralBCSAppForOffice project node in Solution Explorer and select Add ⇒ Content Types for an External Data Source.
5. In the Specify OData Source dialog, enter http://services.odata.org/Northwind/Northwind.svc/.
6. In the Data Source Name, enter Northwind OData Producer. Click Next.
7. In the Select the Data Entities dialog, select Employees and confirm that the Create list instances for the selected data entities check box is checked. Click Finish.
8. Visual
Studio creates an External Content Types node in the Solution Explorer;
this should all be familiar to you from the last exercise.
9. Open Word (2013) but before opening a document enter the phrase employee referral in the search bar and click the search icon. When the employee referral form is found, click it and then click Create.
10. Click on Your Logo Here, delete it, and change the Company Name to Company Inc.
11. If the
Develop tab is not showing above your ribbon, click File ⇒ Options.
Click Customize Ribbon and on the far right click the Developer check
box. Click OK to close the dialog.
12. To add a
content control to the document so the JavaScript in your app for
Office can interact with a named object on the form, click the left
side of the line beside the Employee Name. Click the Developer tab and
click on the leftmost Aa in the Controls group. This is the Rich Text
content control.
13. With the
content control highlighted in the document (if it is not then click
it), click the Properties button in the Controls group in the ribbon.
In the Title text box, enter ccSPUserTitle and click OK.
14. Repeat the
previous step three more times, placing your cursor in the leftmost
position on the line beside E-Mail Address (in the Employee Information
section), and Candidate Name and Phone No (in the Referral Information
section), and provide these respective Title values for each of the
content controls: ccSPUserEmail, ccEmployeeName, and ccEmployeePhone.
15. Select
File ⇒ Options ⇒ Computer and browse to a location of choice to save
this file. If prompted to Save, click OK, but you do not want to
maintain compatibility. Close Word.
16. Return to Visual Studio, right-click the project, and click Add ⇒ New item. Select App for Office, name it EmployeeReferralForm and click Add.
17. In the
Choose the type of app you want to create and where you want it to
appear dialog, uncheck Excel and PowerPoint and click Next.
18. In the
Choose a document for your app for Office dialog, select Insert the app
into an existing document and click Browse to go to the location where
you just saved the Word document. Select the document you saved and
click Finish.
19. Right-click the project, and click Add ⇒ New item. Select List, name it EmployeeReferralLibrary, and click Add.
20. In the Choose List Settings dialog, drop-down the Default (Blank) list, select Document Library and click Next.
21. In the
Choose a template for this document library dialog, select Use the
following document as the template for this library, and click Browse.
The Open file dialog opens with files showing from within your project.
Open the OfficeDocuments folder,
select the Word document, click Open and then click Finish. It’s
important that you select the file that is within your project and not
the original file you saved. The file within your project has been
prepared to be an App for Office template.
22. Visual
Studio opens the new document library in the list designer. Click on
the Columns tab if it is not selected and click the Content Types
button.
23. Click the
Document row to select the entire row, right-click it and select Del to
delete it. Click OK. This allows your content type to be the only one
presented to the user of the list.
24. Click the List tab at the top of the list designer and copy the entire List URL.
25. In Solution Explorer, navigate to the AppManifest.xml file, right-click, and select View Code. Replace just the Pages/Default.aspx portion of the URL with Lists/EmployeeReferralLibrary. When you deploy the app for SharePoint, the list will be the default location to which the app opens.
26. The
StartPage element should look like this:
<StartPage>~appWebUrl/Lists/EmployeeReferralLibrary?{StandardTokens}</StartPage>
27. For the code, in Solution Explorer, expand the Pages node and open the
EmployeeReferralForm.html file. Replace all the XML between the body tags with the following:
<h2>App for Office using External List Data</h2>
<div id="Content"></div>
<div id="showEmployeeInfo"></div>
28. Expand the Scripts node and open the
EmployeeReferralForm.js file. Replace all the JavaScript with the following:
var user;
var appWebURL; // URL of the appWeb
Office.initialize = function (reason) {
$(document).ready(function () {
var $getExternalDataButton = $('<input type="button"
value="Retrieve Employee BCS Data from
SharePoint"/>').appendTo($("#Content"));
$("#Content").append($('<div id="Result"></div>'));
initializeConnectionToSharePoint(function () {
$("#Result").append($("<div>SharePoint references loaded,
click to load data.<div>"));
// Bind to the named Content Controls in the document
createContentControlBindings();
// Automatically load SharePoint user information
// into the Employee Content Controls in the form
Office.select("bindings#ccSPUserTitle")
.setDataAsync(user.get_title(), function () { });
Office.select("bindings#ccSPUserEmail")
.setDataAsync(user.get_email(), function () { });
});
$getExternalDataButton.click(function () {
getEmployees();
});
$(document).on('click','.dataRow', function () {
//identity
var id= $(this).attr('id');
var empFirstName = $('.FirstName[data-identity="' + id + '"]').text();
var empLastName = $('.LastName[data-identity="' + id + '"]').text();
var empHomePhone = $('.HomePhone[data-identity="' + id + '"]').text();
// Get the bound Content Controls for the Employee referral candidate
// and load with the data from the clicked on row in the table.
Office.select("bindings#ccEmployeeName")
.setDataAsync(empFirstName + " " + empLastName, function () { });
Office.select("bindings#ccEmployeePhone")
.setDataAsync(empHomePhone, function () { });
});
});
};
function createContentControlBindings() {
Office.context.document.bindings.addFromNamedItemAsync("ccSPUserTitle", "text",
{ id: "ccSPUserTitle" }, function () { });
Office.context.document.bindings.addFromNamedItemAsync("ccSPUserEmail", "text",
{ id: "ccSPUserEmail" }, function () { });
Office.context.document.bindings.addFromNamedItemAsync("ccEmployeeName", "text",
{ id: "ccEmployeeName" }, function () { });
Office.context.document.bindings.addFromNamedItemAsync("ccEmployeePhone", "text",
{ id: "ccEmployeePhone" }, function () { });
}
function initializeConnectionToSharePoint(functionToExecuteOnReady) {
// Because calling back into SharePoint,
// need to dynamically load SP JavaSript references
var scriptbase = "/_layouts/15/";
$.getScript(scriptbase + "SP.Runtime.js",
function () {
$.getScript(scriptbase + "SP.js", getAppWebAndUser);
}
);
function getAppWebAndUser() {
var context = SP.ClientContext.get_current();
var website = context.get_web();
context.load(website);
user = website.get_currentUser();
context.load(user);
context.executeQueryAsync(onGetAppWebUserSuccess, onGetURLFail);
function onGetAppWebUserSuccess() {
appWebURL = website.get_url();
functionToExecuteOnReady();
}
function onGetURLFail(sender, args) {
$("#Content").append($("<div>Problems connecting to SharePoint: "
+ args.get_message() + "</div>"));
}
}
}
function getEmployees() {
$.ajax({
url: appWebURL +
"/_api/lists/getbytitle('Employees')/items?" +
"$select=BdcIdentity,EmployeeID,LastName,FirstName,Title,HomePhone",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: showEmployees
});
function showEmployees(data) {
var items = [];
// Build table for showing Employees
items.push("<table>");
items.push("<tr><td>Emp ID</td>" +
"<td>Last Name</td>" +
"<td>First Name</td>" +
"<td>Phone Number</td></tr>");
// Make each row and cell uniquely identifiable
$.each(data.d.results, function (key, val) {
items.push('<tr class="dataRow" id="' + val.BdcIdentity + '">' +
'<td class="employeeId" data-identity="'
+ val.BdcIdentity + '">' + val.EmployeeID + '</td>' +
'<td class="LastName" data-identity="'
+ val.BdcIdentity + '">' + val.LastName + '</td>' +
'<td class="FirstName" data-identity="'
+ val.BdcIdentity + '">' + val.FirstName + '</td>' +
'<td class="HomePhone" data-identity="'
+ val.BdcIdentity + '">' + val.HomePhone + '</td></tr>');
});
items.push("</table>");
$("#showEmployeeInfo").html(items.join(''));
}
}
29. Press F5 to start debugging.
30. Log in to the site when the browser opens. Above the ribbon, click Files ⇒ New Document and select EmployeeReferralLibraryContentType.
31. When Word
opens, your document template and TaskpaneApp will load. Notice the
document has already filled in your login employee information.
32. Click the
Retrieve Employee BCS Data from SharePoint button. When the employee
data loads in the task pane, click any employee in the list to see his
data load into the template, as shown in Figure 1.
33. Save the document into the document library if you want to view it in the Word Web app or open it again in Word. Close Word.
34. In the
browser, refresh the document library to see your newly saved file.
View it if you choose to, and then close the browser to stop debugging.
In this exercise you worked a number
of components into an integrated solution. Along with knowing how to
stitch a solution like this together, the key part is seeing how to
write the JavaScript code to retrieve data from SharePoint from an app
for Office when its HTML page is also hosted on SharePoint. Because the
document template is opened in Word from within the context of a
logged-in Office 365 user, you don’t need to be concerned about
authentication to SharePoint. Therefore, after the TaskpaneApp HTML
page is loaded, you can construct the URL for $.getScript() to reach into the /_layouts/15/ directory in your SharePoint site to load and execute the SP.Runtime.js. Upon its success, you load and execute the SP.js.
With these loaded, the stage is set for both JavaScript client-side
object (CSOM) calls and REST-based calls to retrieve the desired data
from SharePoint. First, the Web and user information are retrieved via
CSOM and loaded into variables for later use. Then, when the user
clicks the button in the TaskpaneApp to load the employee data, a REST
call is made to retrieve and display the employee information.
Because the table to display the
employee data is being added to the DOM after the DOM has been loaded,
you need a way to late-bind a click event to the table so when the
users click a row in the table, the appropriate data can be inserted
into the desired document content control. To accomplish this you added
a class named datarow to the <tr> element and an id attribute with the unique BdcIdentity value from the external list data item. Then for each cell in the row, you added a class for the name of the <td> element and a custom data- attribute so the cell data value can be retrieved directly.