In previous versions of SharePoint, developers accessed content and performed operations via server side code called Server Object Model and/or used SharePoint Web Services. Now Microsoft has introduced a new way for developers to communicate with SharePoint Foundation 2010; this third way of writing code is known as Client Object Model. (SharePoint Server Object Model and SharePoint Web Services are still options). The Client Object Model (Client OM) API can be used in .NET based applications, Silverlight applications, and in ECMAScript (JavaScript) that executes in the browser. Although the Client OM API is not as rich as the Server Object Model, it has its own benefits, such as an object-oriented way of accessing SharePoint content without the complexities of Server Object Model and SharePoint Web Services, no packaging and deployment hassles, easy access to content stored in SharePoint list/libraries, quick and easy scripting, etc.
This chapter will focus on ECMAScript (JavaScript) to access the Client OM API. The concepts are same if you want to develop a Silverlight or a .NET application.
Note Silverlight and .NET applications need reference to Microsoft.SharePoint.Client.dll
and Microsoft.SharePoint.Client.Runtime.dll
to access the API. These two dlls can be downloaded from the server where SharePoint 2010 is installed.
The SharePoint Client OM provides an object-oriented way of retrieving SharePoint data. Developers first need to get the client context object; through this context they can access the client objects of a site (any level in a site collection). The Client
object's parent class is ClientObject
and it can be used to get properties of a specific SharePoint object, etc.
Once the client application uses Client OM, the calls are converted into XML request and sent to the SharePoint server. On the server, the XML request is handled by a service called Client.svc
where it translates the XML request into appropriate Object Model calls (SharePoint Server Object Model) and gets the results. After getting the results, Client.svc
translates them into JavaScript Object Notation (JSON) and sends back to the Client Managed Object Model. On the client side, the JSON response is translated into ECMAScript objects for ECMAScript. This process is shown in Figure 7-1.
ECMAScript is a JavaScript-based client-side scripting language for web pages developed by Ecma International and now supported in SharePoint 2010. The first version of ECMAScript was released in June 1997 and latest version (the fifth) was released in Dec 2009. From a developer's point of view, it's just another version of JavaScript and its SharePoint Class Library can be viewed at http://msdn.microsoft.com/en-us/library/ee538253.aspx
. Commonly used JavaScript files for Client OM are CUI.js
, SP.js
, SP.Core.js
, SP.Ribbon.js
, etc. Table 7-1 lists the main classes of ECMAScript for the SharePoint Object Model.
To create a list in SharePoint 2010 site, follow these steps:
Figure 7-2. Select Site Actions More Options
Figure 7-3. Select the Custom List option
Figure 7-4. Select List Tools List Create Column
Note Now you have a list with column Title (Text) and Price (Currency).
In this section you will create an ASPX page to add items into the product list using the Client Object Model in ECMAScript. Follow these steps to create an AddItemForm.aspx
page.
Figure 7-6. The Product folder
AddItemForm.aspx
, as shown in Figure 7-7.
Figure 7-7. Rename the file
Figure 7-8. Open the page in advanced mode
Figure 7-9. The Split tab
Figure 7-10. Now you can create custom content
AddItem()
) inside the PlaceHolderMain, as shown in the following code and in Figure 7-11:
<table style="width: 100%">
<tr>
<td>Title</td>
<td><input id="txtTitle" name="txtTitle" type="text" /></td>
</tr>
<tr>
<td>Price</td>
<td><input id="txtPrice" name="txtPrice" type="text" /></td>
</tr>
<tr>
<td></td>
<td><input name="btnAdd" type="button" value="Add" onclick=
"javascript:AddItem();"/></td>
</tr>
</table>
Figure 7-11. HTML code and resulting text boxes
<script type="text/javascript">
ExecuteOrDelayUntilScriptLoaded(MainFunction, "sp.js");
var objContext = null;
var objWeb = null;
var objList = null;
var objItem = null;
var objListItemCreationInfo = null;
function MainFunction()
{
}
function AddItem()
{
var strTitle = document.getElementById('txtTitle').value;
var strPrice = document.getElementById('txtPrice').value;
objContext = new SP.ClientContext.get_current();
objWeb = objContext.get_web();
objList = objWeb.get_lists().getByTitle("Product");
objListItemCreationInfo = new SP.ListItemCreationInformation();
objItem = objList.addItem(objListItemCreationInfo);
objItem.set_item('Title', strTitle);
objItem.set_item('Price', strPrice);
objItem.update();
objContext.load(objItem);
objContext.executeQueryAsync(Function.createDelegate(this, this.AddItemSuccess),
Function.createDelegate(this, this.AddItemFail));
document.getElementById('txtTitle').value = '';
document.getElementById('txtPrice').value = '';
}
function AddItemSuccess(sender, args)
{
alert('Item added successfully.'),
}
function AddItemFail(sender, args)
{
alert('Item is not added.'),
}
</script>
AddItemForm.aspx
via a browser (e.g. http://sps2k10dev01:5000/NxGen/Lists/Product/AddItemForm.aspx).
Provide the product title and price, and then press the Add button, as shown in Figure 7-12.
Figure 7-12. Product title and price
AllItems.aspx
page (http://sps2k10dev01:5000/NxGen/Lists/Product/AllItems.aspx
) of the product list. You should see the newly added item displayed there, as shown in Figure 7-13.The first step to using the Client Object Model in ECMAScript is to load the SP.js
file, which can be loaded by calling the ExecuteOrDelayUntilScriptLoaded(Func, "sp.js")
method. Along with loading the sp.js
file, this method also calls the MainFunction()
which can be used as OnLoad
or initialized the function on the page.
Note SP.js
is referred to in ECMAScript and Microsoft.SharePoint.Client.dll
and Microsoft.SharePoint.Client.Runtime.dll
are referred to in .NET code to access the Client Object Model. The two dlls could be located at C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14TEMPLATELAYOUTSClientBin
on the server.
Once the page is called, the MainFunction()
executes (which, of course, isn't doing anything in your example). When the Add button is clicked, after filling the text fields, the AddItem()
method is called. In the AddItem()
method, the values from two text boxes are stored in the strTitle
and strPrice
variables, and then the current context of the site is loaded using SP.ClientContext.get_current(),
which is used to load the current site using get_web()
method. Once you have the current site, you can access the lists, document libraries, etc. The current site's lists will be called by the get_lists()
method, and then the product list will be pointed to by calling getByTitle(strListName)
method and will pass it the list name.
The objListItemCreationInfo
object is created to store the information to create the list item and is passed to the List
object by calling the addItem()
method. The item
object is then populated with the values by calling set_item(strColumnName, strValue)
method, and the update()
method is called to add the item to the product list. The current context's load item is called to only load the item
object and to avoid the performance hit of loading all the objects.
The actual execution will take place when the executeQueryAsync()
method of the current context is called. This method executes asynchronously on the server and takes two function names (AddItemSuccess
and AddItemFail
) as parameters to call them if the execution succeeds or fails respectively. One of the AddItemSuccess()
and AddItemFail()
functions will be called and will display the success or failure method to show how the execution of executeQueryAsync()
went.
Creating an Edit form is much like creating the Add form, so I will skip some of the steps and jump directly into the main functionality.
EditItemForm.aspx
and add two HTML text boxes (txtTitle and txtPrice) and one HTML button (btnUpdate, which will call the JavaScript function UpdateItem()
) inside PlaceHolderMain, as shown here and in Figure 7-14:
<table style="width: 100%">
<tr>
<td>Title</td>
<td><input id="txtTitle" name="txtTitle" type="text" /></td>
</tr>
<tr>
<td>Price</td>
<td><input id="txtPrice" name="txtPrice" type="text" /></td>
</tr>
<tr>
<td></td>
<td><input name="btnUpdate" type="button" value="Update" onclick=
"javascript:UpdateItem();"/></td>
</tr>
</table>
<script type="text/javascript">
ExecuteOrDelayUntilScriptLoaded(MainFunction, "sp.js");
var strID = null;
var objContext = null;
var objWeb = null;
var objList = null;
var objItem = null;
var objCollectionListItem = null;
function MainFunction()
{
strID = QueryString("ID");
objContext = new SP.ClientContext.get_current();
objWeb = objContext.get_web();
objList = objWeb.get_lists().getByTitle("Product");
var objQuery = new SP.CamlQuery();
objQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name="ID"/><Value Type=
"Number">'+ strID +'</Value></Eq></Where></Query><ViewFields><FieldRef Name="Title"/>
<FieldRef Name="Price"/></ViewFields></View>'),
objCollectionListItem = objList.getItems(objQuery);
objContext.load(objCollectionListItem);
objContext.executeQueryAsync(Function.createDelegate(this, this.LoadItemSuccess),
Function.createDelegate(this, this.LoadItemFail));
}
function LoadItemSuccess(sender, args)
{
var listItemEnumerator = objCollectionListItem.getEnumerator();
//This loop will run only once
while (listItemEnumerator.moveNext())
{
var objTempItem = listItemEnumerator.get_current();
document.getElementById('txtTitle').value = objTempItem.get_item('Title'),
document.getElementById('txtPrice').value = objTempItem.get_item('Price'),
}
}
function LoadItemFail(sender, args)
{
alert('Item loading failed.'),
}
function QueryString(parameter)
{
var loc = location.search.substring(1, location.search.length);
var param_value = false;
var params = loc.split("&");
for (i=0; i<params.length;i++)
{
param_name = params[i].substring(0,params[i].indexOf('='));
if (param_name == parameter)
{
param_value = params[i].substring(params[i].indexOf('=')+1)
}
}
if (param_value)
{
return param_value;
}
else
{
return false;
}
}
function UpdateItem()
{
var strTitle = document.getElementById('txtTitle').value;
var strPrice = document.getElementById('txtPrice').value;
objContext = new SP.ClientContext.get_current();
objWeb = objContext.get_web();
objList = objWeb.get_lists().getByTitle("Product");
objItem = objList.getItemById(strID);
objItem.set_item('Title', strTitle);
objItem.set_item('Price', strPrice);
objItem.update();
objContext.executeQueryAsync(Function.createDelegate(this, this.UpdateItemSuccess),
Function.createDelegate(this, this.UpdateItemFail));
document.getElementById('txtTitle').value = '';
document.getElementById('txtPrice').value = '';
}
function UpdateItemSuccess(sender, args)
{
alert('Item updated successfully.'),
}
function UpdateItemFail(sender, args)
{
alert('Item is not updated.'),
}
</script>
EditItemForm.aspx
via browser and pass it a valid ID of the item already existing in the Product list (e.g. http://sps2k10dev01:5000/NxGen/Lists/Product/EditItemForm.aspx?ID=9)
.As mentioned earlier, the first step to using the Client Object Model in the ECMAScript is to load the SP.js
file, which can be loaded by calling the ExecuteOrDelayUntilScriptLoaded(Func, "sp.js")
method. Along with loading the sp.js file
, this method also calls the MainFunction()
, which can be used as OnLoad or to initialize a function on the page.
Once the page is called, the MainFunction()
executes, which will call QueryString()
to get the value of the querystring ID. The Product list is called by getting the current context, then the current site and all the lists in the current site. objQuery
will hold the CAML (Collaborative Application Markup Language) query XML to execute against the list to retrieve the list content. In the example, the following CAML is used:
<View>
<Query>
<Where>
<Eq><FieldRef Name="ID"/><Value Type="Number">'+ strID+'</Value></Eq>
</Where>
</Query>
<ViewFields>
<FieldRef Name="Title"/><FieldRef Name="Price"/>
</ViewFields>
</View>
This CAML query tells the API to get the items where the ID column value is provided by the strID
variable. In <ViewFields/>
tag, two columns have been mentioned that need to be returned for the selected items.
If the execution of the executeQueryAsync()
method succeeds, then LoadItemSuccess()
will iterate through all the returned items and will populate the text boxes for the user to update the values.
The Update button will call the UpdateItem()
method, which will get the list item by ID by calling the getItemById(intID)
method of the list object. It will set the new values for the columns and update the item by calling the update()
method of the item object and then calling the executeQueryAsync()
method.
The Edit form (EditItemForm.aspx
) can be upgraded with the delete functionality easily. The process is similar to updating a list item but you call a delete method instead of an update method.
EditItemForm.aspx
in SharePoint Designer.DeleteItem()
, as shown in Figure 7-17.
Figure 7-17. The delete functionality
<script>
tag.
function DeleteItem()
{
if(window.confirm('Are you sure you want to delete this item?'))
{
objContext = new SP.ClientContext.get_current();
objWeb = objContext.get_web();
objList = objWeb.get_lists().getByTitle("Product");
objItem = objList.getItemById(strID);
objItem.deleteObject();
objContext.executeQueryAsync(Function.createDelegate(this,
this.DeleteItemSuccess), Function.createDelegate(this, this.DeleteItemFail));
}
}
function DeleteItemSuccess(sender, args)
{
window.location = "AllItems.aspx";
}
function DeleteItemFail(sender, args)
{
alert('Item is not updated.'),
}
Note If you plan to use this code separately, don't forget to add the following line in the <script>
tag:
ExecuteOrDelayUntilScriptLoaded(MainFunction, "sp.js");
EditItemForm.aspx
page via browser and pass the ID of an existing item. (e.g. http://sps2k10dev01:5000/NxGen/Lists/Product/EditItemForm.aspx?ID=7)
and press the Delete button, as shown in Figure 7-18.The item will be deleted and user will be redirected to the AllItems.aspx
page where the deleted item does not exist, as shown in Figure 7-19.
Once the Delete button is clicked, the item is loaded by calling the getItemById(intID)
method of the list
object and is deleted by calling the deleteObject()
method of the item
object. Once again, the actual execution will be taken placed when executeQueryAsync()
is called.
While using SharePoint Client OM in .NET or Silverlight application, both ExecuteQuery()
and ExecuteQueryAsync()
are available to developers. ExecuteQuery()
is a synchronous call, which means the client application will wait for the server's response before jumping onto next line of code. ExecuteQueryAsync()
is an asynchronous call, so code continues to execute; the client application doesn't wait for server's response and will execute the next line of code. Each function has its advantages and disadvantages. For example, if the next piece of code needs input from server, it's okay to use ExecuteQuery()
; however, if the server's response gets delayed, the application will simply hang there. This problem is solved by ExecuteQueryAsync()
where the client application(especially when using the Client OM API in the browser) doesn't wait for the server response so the application won't hang if there's a delay in the response from server. Server response delay can be caused by multiple things such as network traffic, huge calculation, slow servers, etc.
Note While executing the code, developers should massage the code to use ExecuteQueryAsync()
to avoid hanging the browser due to server response delay. If ExecuteQuery()
has been used in the application and browser hangs while waiting for server response, there is a good chance that the whole browser instance will crash; that means any applications running in other tabs could lose data. In ECMAScript, only the executeQueryAsync()
method available and that is being used in this chapter.
ECMAScript is a JavaScript-based client-side scripting language that is now supported in SharePoint 2010 and can be used to access Client Object Model. Users can write ECMAScript in an ASPX page for SharePoint 2010 sites and can manipulate the SharePoint content without the code compilation, Server Object model, or getting involved in the complexities of web services.