JAVASCRIPT

Alongside the Managed .NET Client-Side Object Model (Managed CSOM) is the JavaScript Client Object Model (JS CSOM).


NOTE See the previous section, “Managed Code (.NET),” for background foundational information about the CSOM that isn’t repeated in this section.

The primary purpose of the JS CSOM is to allow JavaScript code running on pages within the context of SharePoint to talk back to SharePoint without requiring a full-page postback. It is not designed or intended for developers to use outside of the context of pages served from SharePoint.

Similar to the Managed CSOM, the JS CSOM also is built to batch requests to ensure performance. However, one of the fundamental differences is that the JS CSOM is designed with asynchronous calls and callbacks in mind. This ensures that transactions that take some time to complete don’t potentially block the calling thread, possibly impacting the UI of your application.

To access the JS CSOM the calling page must reference the following two files:

  • SP.Runtime.js
  • SP.js

Each of these is located in the /_layouts/15/ directory under each SharePoint site; for example, http://myserver/sitename/_layouts/15/SP.js.

You can also find these files on any SharePoint 2013 server in the following location:

%ProgramFiles%Common FilesMicrosoft Shared
web server extensions15TEMPLATELAYOUTS

NOTE Although the JS CSOM libraries are available, sometimes simple REST/OData HTTP-based calls might be just as easy for you to use. If you are familiar with making REST/JSON-based calls then they might also be worth considering. However, you would lose some of the benefits of the CSOM, such as automatic batching.

Setup

By default, pages that run within the context of SharePoint typically have the appropriate JavaScript references already defined in the master page. This means you shouldn’t need to reference them in each page of your application. However, understanding what it means to be within the context of SharePoint is important. It means that the page is served from the same domain as SharePoint, rather than from another location such as in Azure. In cloud-hosted SharePoint apps, this is the default. Pages are loaded and served from SharePoint, which is possible because they can contain only out-of-the-box SharePoint controls, HTML, and JavaScript, so no custom code runs within the SharePoint process itself.

One way to tell whether your page uses the SharePoint master page is to look for the following Page declaration at the top of the page:

<%@ Page Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, 
Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, 
PublicKeyToken=71e9bce111e9429c" 
MasterPageFile="~masterurl/default.master" language="C#" %>

If you have a page that doesn’t inherit the SharePoint master page then you must include references to the appropriate JavaScript CSOM files. An example of this would be in an App Part when you don’t want the full SharePoint master page wrapping your App Part’s user interface.

To add the references manually you must include the following script references:

<script type="text/javascript" 
src="https://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.runtime.debug.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.debug.js"></script>

If your page is served from outside of the SharePoint site, such is the case with Autohosted apps (served from Azure) or Provider-hosted apps, then you must dynamically generate the script includes in JS to ensure they include the fully qualified domain name (FQDN) in the URL. This is because you need to have the JS files served from the SharePoint Server itself to ensure the browser doesn’t block the JS CSOM calls because of cross-site scripting protections.

To do this you can use the SPHostUrl query string parameter passed to your SharePoint app as follows:

<script type="text/javascript">
    var hosturl;
    $(document).ready(function () {
        hosturl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
        var scriptbase = hostweburl + "/_layouts/15/";
 
        $.getScript(scriptbase + "SP.Runtime.js",
            function () {
                $.getScript(scriptbase + "SP.js", scriptLoaded);
            }
        );
    });
 
    function scriptLoaded () {
    // your code goes here
    }
 
    function getQueryStringParameter(paramToRetrieve) {
        var params = document.URL.split("?")[1].split("&");
        var strParams = "";
        for (var i = 0; i < params.length; i = i + 1) {
            var singleParam = params[i].split("=");
            if (singleParam[0] == paramToRetrieve)
                return singleParam[1];
        }
    }
</script>

In the preceding code the JQuery $(document).ready method is called when the page has loaded and it’s safe for the script to continue. The code then uses the getScript method to dynamically load the JavaScript files. It also uses the SPHostUrl query string parameter passed to dynamically ensure it is retrieving the files from the originating SharePoint site. After that call completes, the scriptLoaded method is called. The ScriptLoaded method is the location you can safely place your JS CSOM code.


NOTE For demonstration purposes all the examples in the rest of this chapter use a cloud-hosted SharePoint app in Office 365 and use the Napa Office 365 development tools. These items enable you to develop lightweight cloud-hosted apps within a browser in a SharePoint Online developer site.
These items are available in the Office 365 app marketplace. Install them into your developer site prior to continuing.

Querying

Similarly to the Managed CSOM, the JS CSOM also includes built-in batching and filtering. These features are especially important in client applications where the browser executing the code is always remote and often on an unknown quality of connection. To ensure your application stays responsive and fast you must take measures to make as few requests as possible and only return the data you really need.

Prior to making any requests you must set up a ClientContext. To get the context associated with the site and page the script is running on, use the get_Current() method:

var clientContext = context = new SP.ClientContext.get_current();

You can then start requesting data. One of the simplest requests you can make is for the information about the site, like so:

var web;
web = clientContext.get_web();
clientContext.load(web);

Now you are ready to make the request to the server. Because you don’t want to block the application thread processing while this potentially long-running task is in progress, you provide callback functions that will be called either after the operation completes or if an error occurs.

To do this, make a call to executeQueryAsync like this:

clientContext.executeQueryAsync(
        myQuerySucceeded, 
        myQueryFailed);

In the myQuerySucceeded function you can start using the objects you asked for:

function onQuerySucceeded() {alert(this.web.Title);}

Additionally, your application should be able to handle when errors occur. This might be due to connectivity issues, for example, like the following:

function myQueryFailed(sender, args) {alert('Call to SharePoint failed :('),}

When querying lists and libraries you have the choice of querying for a specific item whose ID you already know using the getItemById(id) method, or with a query using the getItems(query) method. The latter is slightly more complex in that you need to set up the query against that list using CAML syntax. The following sample code shows querying a simple list for all items whose Title column equals “Foo”:

    var list = listContext.get_web().get_lists().getByTitle('My Custom List'),
    
    var camlQuery = new SP.CamlQuery();
 
    camlQuery.set_viewXml(
    '<View><Query><Where><Eq><FieldRef Name='Title'/>' + 
    '<Value Type='Text'>New Item 1</Value></Eq></Where></Query>' + 
    '<RowLimit>10</RowLimit></View>' );
 
    items = list.getItems(camlQuery);
 
    context.load(items);
    context.executeQueryAsync(myQuerySucceeded, myQueryFailed);

You can use the CAML query to carefully construct the exact query against the list you want to make and also the data you want to bring back.

To create and manipulate list items, use the ListItemCreationInformation object as shown in the following code example. This gives you a context object that allows you set up the item prior to sending it to the server along with the data you want to create:

var newListItem;
 
function createItems()
{
    var listContext = new SP.AppContextSite(context, hostUrl);
    var list = listContext.get_web().get_lists().getByTitle('My Custom List'),
    
    var itemCreateInfo = new SP.ListItemCreationInformation();
    newListItem = list.addItem(itemCreateInfo);
         newListItem.set_item('Title', 'Created via JS CSOM!'),
         newListItem.update();
         context.load(newListItem);
         context.executeQueryAsync(onCreateListItemsSuccess,onCreateListItemsFail);
         }
 
function onCreateListItemsSuccess() {
    alert('New ListItem created: ' + newListItem.get_id());
}
 
// This function is executed if the above call fails
function onCreateListItemsFail(sender, args) {
    alert('Failed to create list item. Error:' + args.get_message());
}

For updates you simply get the list item in question, make the update to the data, and then call update() on it like so:

var listItem = list.getItemById(1);
listItem.set_item('Title', 'Updated via JS CSOM'),
listItem.update();

You can try out these APIs and techniques in the following exercise to get a better feel for how they work with SharePoint Online using the new Napa developer tools.


TRY IT OUT: Using the JavaScript Client-Side Object Model in a SharePoint-Hosted App Using Napa for Office 365
In this exercise you create a SharePoint application using only JavaScript and the Napa Office 365 development tools. You must have the Napa application installed from the Office 365 marketplace prior to starting this exercise. The full JavaScript source for this exercise is available in the code download in the JavaScriptCSOMApp.js file.
1. Ensure you have Napa Office 365 Development Tools installed in your development site in Office 365.
2. Click Site Contents in your site navigation to see a list of all apps installed in your site.
3. Locate Napa Office 365 Development Tools in the list and click it as shown in Figure 9-3.
4. Click Add New Project.
5. Select App for SharePoint and enter MyFirstJavaScriptApp in the Project name box. Click Create to continue. Napa creates a set of template files and folders for you. Explore the structure and get familiar with the layout of the application.
6. Open the Scripts folder and then open the App.js file. This is the default file that contains the JavaScript for your application.
7. At the bottom of the file add the following code:
function getParameterByName(name)
{
  name = name.replace(/[[]/, "[").replace(/[]]/, "]");
  var regexS = "[?&]" + name + "=([^&#]*)";
  var regex = new RegExp(regexS);
  var results = regex.exec(window.location.search);
  if(results == null)
    return "";
  else
    return decodeURIComponent(results[1].replace(/+/g, " "));
}
8. Replace the sharePointReady() function with the following code. This gets the host URL for use later.
var hostUrl;
 
function sharePointReady() {
    context = new SP.ClientContext.get_current();
    web = context.get_web();
         hostUrl = getParameterByName('SPHostUrl'),
    createList();
}
9. Directly after the sharePointReady() function insert the following code. This creates a new list.
var newList;
 
function createList() {
    var hostContext = new SP.AppContextSite(context, hostUrl);
    web = hostContext.get_web();
    
    var newListInfo = new SP.ListCreationInformation();
    newListInfo.set_title('My Sample List'),
    newListInfo.set_templateType(SP.ListTemplateType.genericList);
 
    newList = web.get_lists().add(newListInfo);
 
    context.load(newList);
    context.executeQueryAsync(onCreateListSucceeded, onFailed);
}
 
function onCreateListSucceeded() {
    alert('New list created: ' + newList.get_title());
}
 
// This function is executed if the above call fails
function onFailed(sender, args) {
    alert('Failed. Error:' + args.get_message());
}
10. Click the Run Project button in the bottom left of the window to test out the application. When it completes, a message appears like the one shown in Figure 9-4.
11. Right-click the launch link and open your app in a new window to start your application.
12. A JavaScript alert message appears, stating, “Failed. Error: Access denied. You do not have permission to perform this action or access this resource.” This is supposed to happen. The reason is that you have not yet given your application permissions to create lists in the app’s host Web. Click OK to continue then close the window. Click Close in the Launch App dialog in Napa to get back to your code.
13. In the lower left of the window click the wrench icon to open the Property panel for your application, as shown in Figure 9-5.
14. Click into the Permissions tab and set the permissions for Web under Content to Full Control.
15. Run the project again using the Run Project button in the bottom left of the window. A permissions request window appears, asking you to grant the application full control of the site. Click Trust It.
16. An alert window appears, stating, “New list created: My Sample List.” Click OK.
17. Check that your list was created by clicking the link in the top left of the page to get to your developer site. Click Site Content and find the new list called My Sample List. Click it to open the list. Currently, no data is in it.
18. Within the sharePointReady function, change the createList(); call to createItems();.
19. After the sharePointReady function, add the following code:
function createItems()
{
    var listContext = new SP.AppContextSite(context, hostUrl);
    var list = listContext.get_web().get_lists().getByTitle('My Sample List'),
    
    for(var i=0; i < 10; i++)
    {
        var itemCreateInfo = new SP.ListItemCreationInformation();
        var newListItem = list.addItem(itemCreateInfo);
             newListItem.set_item('Title', 'Created via JS CSOM! - ' + i);
        newListItem.update();
             context.load(newListItem);
    }
         context.executeQueryAsync(onCreateListItemsSuccess,onFailed);
}
 
function onCreateListItemsSuccess() {
    alert('New ListItems created'),
}
20. Run and launch the app again using the Run Project button in the bottom left of the window. This time an alert appears stating, “New ListItems created.
21. Check the list in the SharePoint site to ensure the data has been created. You should see ten new items created in the list.
22. Within the sharePointReady function, change the createItems(); call to updateListItem();.
23. Directly after the sharePointReady function, insert the following code:
var updatedItem;
 
function updateListItem() {
    var listContext = new SP.AppContextSite(context, hostUrl);
    var list = listContext.get_web().get_lists().getByTitle('My Sample List'),
    
    var listItem = list.getItemById(1);
    listItem.set_item('Title', 'Updated via JS CSOM'),
    listItem.update();
 
    context.load(listItem);
    context.executeQueryAsync(onUpdateItemSucceeded, onFailed);
}
 
function onUpdateItemSucceeded() {
    alert('Updated item!'), 
}
24. Run and launch the app again. This time an alert appears stating, “Updated item!”. Again, check the SharePoint list to see that the first item in the list has been updated.
25. Within the sharePointReady function, change the updateListItem(); call to getItems();.
26. Directly after the sharePointReady function, insert the following code:
var items;
 
function getItems()
{
    var listContext = new SP.AppContextSite(context, hostUrl);
    var list = listContext.get_web().get_lists().getByTitle('My Sample List'),
    
    var camlQuery = new SP.CamlQuery();
    camlQuery.set_viewXml(
        '<View><Query><Where><Eq><FieldRef Name='Title'/>' + 
        '<Value Type='Text'>Updated via JS CSOM</Value></Eq></Where></Query>' + 
        '<RowLimit>10</RowLimit></View>'
    );
    items = list.getItems(camlQuery);
    context.load(items);
    context.executeQueryAsync(onGetListItemsSuccess,onFailed);
}
 
function onGetListItemsSuccess() {
    var listItemEnumerator = items.getEnumerator();  
    
    while (listItemEnumerator.moveNext()) {
        var item = listItemEnumerator.get_current();
        alert(item.get_item('Title'));
    }
}
27. Run and launch the app again. An alert appears stating, “Updated via JS CSOM” indicating that the app was able to query the list for the item it previously updated.
How It Works
In this exercise you created a SharePoint-hosted app using the new Napa tools available in Office 365. These tools allow for lightweight application development within a browser environment without requiring any client-side installation. The app used the JavaScript CSOM and then created a new list using the SP.AppContextSite method to call into the host Web and create and manipulate data. This call is necessary to ensure SharePoint brokers the calls to the host Web. If you attempted to make the calls directly to the host Web the browser would stop you due to cross-site scripting security requirements because the two sites are on a different domain.
The app first created a brand-new list based on the generic list type (the same as creating a custom list via the Web UI) and then inserted 10 new list items into it. Finally, the app updated one of those list items and then queried the list for that newly updated item. The JS CSOM wraps the underlying API calls to SharePoint for you and provides convenient wrapper objects and methods.
When you ran the application Napa packaged the application into an application package (.app file) and then deployed and installed it in SharePoint for you.


WATCH THE REST/ODATA CALLS WITH FIDDLER
If you are interested in seeing the HTTP(S) calls to SharePoint from the JavaScript you can do so with a tool called Fiddler. You can download Fiddler from http://www.fiddler2.com. Using Fiddler you can see all the HTTP traffic between your computer and another such as Sharepoint.com, where Office 365 is hosted. When watching Fiddler look for POST requests to /_api/SP.AppContextSite(@target)/web/lists. You can see JSON payloads being sent and received from SharePoint.

Security and Cross-Domain Calls

JavaScript engines in modern browsers include security mechanisms that do not allow JavaScript to make calls across domains. This means that scripts can only get data from the domain where they were served. For example, if your page is served from http://www.myserver.com then JavaScript will not be allowed to make calls to http://www.someotherserver.com. This is to stop cross-site scripting attacks (XSS). Because of this limitation SharePoint also provides some mechanisms that let your SharePoint JS calls get at information in other domains including:

  • SP.AppContextSite
  • Web proxy

The SP.AppContextSite helper allows you to set up the CSOM ClientContext to make calls to other SharePoint sites. This site could be the host website or another site collection or server entirely. This helper proxies the calls you make via the SharePoint site on the domain where your JavaScript was served, thus getting around the cross-site scripting issues. You must use this technique if you are using Office 365 and your app is hosted on another domain, or if you are using app isolation for application deployment on premises. The latter option creates a subdomain just for your application. Your script will, therefore, need to call out beyond its own domain, and AppContextSite helps with that.

Additionally, you can use the Web proxy SharePoint to call other non-SharePoint endpoints. To use it you must create an SP.WebRequestInfo object and set up the URL and method for the call you want to make as follows:

var context = SP.ClientContext.get_current();
 
var crossDomainRequest = new SP.WebRequestInfo();
 
crossDomainRequest.set_url("http://looselytyped.net/feed/");
crossDomainRequest.set_method("GET");
 
var response = SP.WebProxy.invoke(context, crossDomainRequest);

This code proxies the call to the remote endpoint via SharePoint and returns the results. You can use this technique to call out to any HTTP/HTTPS-enabled endpoint; however, always remember the call goes through SharePoint and is therefore open to being viewed by someone with access to that server/service. HTTPS will not help because the call to SharePoint will be terminated and decrypted on the SharePoint Server prior to the request being made to the destination endpoint. However, this feature allows developers to get around many of the intricacies of cross-site scripting that are otherwise too complex to solve.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.42.168