Alongside the Managed .NET Client-Side Object Model (Managed CSOM) is the JavaScript Client Object Model (JS CSOM).
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:
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
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.
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.
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, " ")); }
var hostUrl; function sharePointReady() { context = new SP.ClientContext.get_current(); web = context.get_web(); hostUrl = getParameterByName('SPHostUrl'), createList(); }
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()); }
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'), }
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!'), }
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')); } }
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:
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.
3.147.42.168