Chapter 13: SharePoint Client Object Model and jQuery (Professional SharePoint Branding and User Interface Design)

Summary: This chapter discusses objects that are supported by the Client Object Model, how to update a site title by using the Client Object Model, common list operations, and using jQuery with SharePoint 2010.

Applies to: Business Connectivity Services | SharePoint Foundation 2010 | SharePoint Server 2010 | Visual Studio

This article is an excerpt from Professional SharePoint Branding and User Interface Design by Randy Drisgill, John Ross, Jacob J. Sanford, and Paul Stubb, published by Wrox Press (ISBN 978-0-470-58463-7, copyright © 2010 by Wrox, all rights reserved). No part of these chapters may be reproduced, stored in a retrieval system, or transmitted in any form or by any means—electronic, electrostatic, mechanical, photocopying, recording, or otherwise—without the prior written permission of the publisher, except in the case of brief quotations embodied in critical articles or reviews.

Contents

  • Introduction

  • Understanding the Client Object Model

  • Updating the Site Title Using the Client Object Model

  • Common List Operations

  • Using jQuery with SharePoint 2010

  • Summary

  • About the Authors

Click to grab code  Download code

Introduction

There are two basic approaches to accessing data programmatically in Microsoft SharePoint 2010. The first approach is to use the SharePoint API on the server. When you run code directly on the SharePoint server, the SharePoint API gives you complete control over all aspects of SharePoint 2010 and the data. If your application is not running on the server and needs to access the SharePoint data, you need to use the SharePoint web services. The web services offer similar functionality compared to the SharePoint API, although not every function is covered.

In SharePoint 2010, you have another option when programming against SharePoint data: the Client Object Model. The Client Object Model is a new approach to remotely programming against SharePoint data. Although using web services gives you broad coverage to SharePoint features, using the programming model and API is very different from using the server API. This makes it difficult for developers, as they need to learn two completely different programming models. Also, calling web services from JavaScript clients is complicated and requires a lot of manual XML creation and manipulation. The Client Object Model solves all these issues, making client-side programming easy and straightforward.

The Client Object Model is really three separate object models, one for the .NET CLR, one for Silverlight, and one for JavaScript. The .NET CLR version is used to create applications such as WinForms, Windows Presentation Foundation (WPF), and console applications, as well as PowerShell scripts. The Silverlight version works with both in-browser and out-of-browser Silverlight applications. The JavaScript version enables your Ajax and jQuery code to call back to SharePoint. You will read more about the Silverlight version in Chapter 14: Silverlight and SharePoint Integration (Professional SharePoint Branding and User Interface Design). We are not going to go into the .NET CLR version in this chapter, but as you will see in Chapter 14, once you learn how the Client Object Model works, you can easily program against any version. In this chapter, you will see how the Client Object Model works with JavaScript and jQuery to perform some common development tasks.

Understanding the Client Object Model

Understanding how the Client Object Model works will help you be more effective across all three versions. As shown in Figure 13-1, the Client Object Model fundamentally is a new Windows Communication Foundation (WCF) SharePoint service called Client.svc and three proxies: .NET CLR, Silverlight, and JavaScript. You program against the client proxies just as you do with any service. Calls to and from the server are sent in batches to increase network efficiency.

Figure 1. Client Object Model Architecture

Client Object Model architecture

Objects supported by the Client Object Model

One of the first questions that comes up when talking about the Client Object Model is, "What can you do with it?" Again, understanding how the Client Object Model works will help you appreciate its capabilities and limitations. The Client Object Model proxies are based on the Microsoft.SharePoint.dll. Right away this establishes what you can do to this API. The Microsoft.SharePoint API supports the most common objects, such as sites, webs, content types, lists, folders, navigations, and workflows. Obviously, this is not an exhaustive list. So, how do you find out if a particular object is supported in the Client Object Model? Fortunately, the help documentation for SharePoint 2010 is very good, and you can find the complete list by looking at the Microsoft.SharePoint.Client Namespace on MSDN.

Another way to find out if a particular object is supported is to look at the attributes on the Microsoft.SharePoint API. Remember that the client proxies are created from the server API (Microsoft.SharePoint Namespace). The tool knows what to put in the client proxies by looking for the attribute named ClientCallableTypeAttribute. The Client Object Model does not require a reference to the server assemblies.

The ClientCallableTypeAttribute also specifies the name to call the object in the proxy. This brings up another important point about the Client Object Model. The names in the Client Object Model have been cleaned up a little by removing the 'sp' from the beginning of most of the objects. But knowing how the Client Object Model is implemented enables you to look in the help documentation and see what the server object is and what the client object is called. For example, open the help page for the SPSite class. In the Syntax section at the top of the help topic, you can see the ClientCallableTypeAttribute and the name that it will be called in the proxy classes.

[ClientCallableTypeAttribute(
Name = "Site",
ServerTypeId = "{E1BB82E8-0D1E-4e52-B90C-684802AB4EF6}")]
[SubsetCallableTypeAttribute]
public class SPSite : IDisposable

At the heart of the Client Object Model is the ClientContext class, the object used to access the objects returned from the server and the queries sent to the server. The first step to programming the Client Object Model is to always get a reference to the current ClientContext using the static method on the ClientContext class, SP.ClientContext.get_current(). You will see how to use the ClientContext class in each of the examples throughout this chapter.

Although it is not possible to go into great depth about the entire Client Object Model API here, you should now have an understanding of how the Client Object Model works, and how to figure out what's in the client API, and how it maps to the server API. This was one of the goals of the SharePoint team: to make it easy for someone who already knows the server API to be productive quickly on the client API. Let's take a look at how to program with the Client Object Model in practice by walking through a few common scenarios.

The two main scenarios you will see are how to use the Client Object Model to read and write properties of the SharePoint site, and how to read and write data from the SharePoint List.

Updating the Site Title Using the Client Object Model

One of the first examples to work with is to retrieve and update the site title. This is a very simple example, but it shows some of the basic patterns of using the Client Object Model.

To retrieve and update a site title

  1. Open Visual Studio and create a new empty SharePoint project called ClientOMProject.

  2. Add a Visual Web Part project item to the project and name it ChangeTitleWebPart. Using a Visual Web Part will require this to be a farm solution.

  3. Open the ChangeTitleWebPart.ascx page. Click the Design button at the bottom of the page to switch between Source view and Design view.

  4. Add an HTML textbox and a button. Once in Design view, drag an Input (Text) control and an Input (Button) control from the HTML section of the Toolbox pane on the left side.

  5. Add the button click handler. Double-click the button to create the JavaScript click event handler. Visual Studio will generate the following code for you.

    <script language="javascript" type="text/javascript">
    // <![CDATA[
      function Button1_onclick() {
    
      }
    
    // ]]>
    </script>
    
    <p>
      <input id="Text1" style="width: 229px" type="text" />&nbsp;
      <input id="Button1" type="button" value="button"
        onclick="return Button1_onclick()" /></p>
    
  6. Call the method to retrieve the site's title property. You need to use the Client Object Model to retrieve the site's title property, but you need to make sure the Client Object Model is loaded first. Add the following code inside your script tag to ensure the Client Object Model is ready before you use it.

    ExecuteOrDelayUntilScriptLoaded(GetTitle, "sp.js");

  7. Create the GetTitle method to retrieve the site's title property. In the previous step, you added code to call the GetTitle method when the Client Object Model was ready. Now you will implement the GetTitle method using the Client Object Model. Add the following code to retrieve the site's title property.

    var site;
      var context;
    
      function GetTitle() {
        //Get the current client context
        context = SP.ClientContext.get_current();
    
        //Add the site to query queue
        site = context.get_web();
        context.load(site);
    
        //Run the query on the server
        context.executeQueryAsync(onQuerySucceeded, onQueryFailed);
      }
    

    First you define the site and context variable to hold a reference for later. In the GetTitle function, you first get a reference to the current client context. This is the context that the page is running in, which in this example is intranet.contoso.com. The second step is to define which objects you want returned and load them onto the context's query queue using the load method. The last step is to execute the calls on the server. In Silverlight and JavaScript this is an asynchronous call, so you will need to define a succeeded and failed callback handler.

  8. Implement the failed callback handler. If your call to the server fails, the failed callback handler will fi re. The callback provides some information to help you debug the problem such as the error message and call stack information. Add the following code to implement a failed callback handler that will display an alert box with the error message.

    function onQueryFailed(sender, args) {
      alert('request failed ' + args.get_message() +
        '\n' + args.get_stackTrace());
    }
    
  9. Implement the succeeded callback handler. Add the following code to set the value of the textbox to the site's title property.

      function onQuerySucceeded(sender, args) {
        document.getElementById("Text1").value = site.get_title();
      }
    
  10. Update the site's title on the button click event. Up to this point you have retrieved the Site's title, now you will add the ability to update the title. Add the following code to the button click handler.

    function Button1_onclick() {
      //Update the Site's title property
      site.set_title(document.getElementById("Text1").value);
      site.update();
    
      //Add the site to query queue
      context.load(site);
    
      //Run the query on the server
      context. executeQueryAsync(onTitleUpdate, onQueryFailed);
    }
    
    function onTitleUpdate(sender, args) {
    }
    
  11. Press F5 to run the application. Once the site opens, you will need to add the ChangeTitleWebPart to the page. You should see something similar to Figure 2.

    Figure 2. Example site page

    Example site page

  12. Refresh the page. You may have noticed that the title does not appear to update when you click the button. In fact, it does update but you will need to refresh the page to see the changes. Add the following code to refresh the page after the title is updated.

    function onTitleUpdate(sender, args) {
      SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK);
    }
    

This code actually uses the new SharePoint dialog framework APIs to perform the page refresh.

Running the application now will display the site's title in the text box and then set the site's title when you click the button. After the title is updated, the page refreshes to show the new site title.

This is a very simple example, but it clearly demonstrates a code pattern for using the Client Object Model: Define the objects to retrieve, load them on the query queue, execute them on the server, and handle the callback. As you look at more complex examples in the next section, you will use this pattern over and over again.

Common List Operations

Now that you have a good understanding of the fundamentals, let's look at a few of the most common tasks you will use the Client Object Model for: reading and writing SharePoint list data. In this sample, you will add a Visual Web Part to the solution and add buttons to call the various operations. You also will see how to use a separate JavaScript fi le to contain most of the Client Object Model code to call SharePoint.

To read and write SharePoint list data

  1. Add the following code to your Visual Web Part. This code will add five buttons for the different operations and some boilerplate code to call the functions. It also contains a reference to the external ListOperations.js file.

    <script src="/SiteAssets/ListOperations.js" type="text/javascript"></script>
    
    <script language="javascript" type="text/javascript">
    // <![CDATA[
    
      function CreateButton_onclick() {
        CreateList();
      }
    
      function AddButton_onclick() {
        AddListItem();
      }
    
      function ReadButton_onclick() {
        ReadListItem();
      }
    
      function UpdateButton_onclick() {
        UpdateListItem();
      }
    
      function DeleteButton_onclick() {
        DeleteListItems();
      }
    
      // ]]>
    </script>
    
    <p><input id="CreateButton" type="button" value="Create List"
    style="width: 150px" onclick="CreateButton_onclick()" /></p>
    <p><input id="AddButton" type="button" value="Add List Item"
    style="width: 150px" onclick="AddButton_onclick()" /></p>
    <p><input id="ReadButton" type="button" value="Read List Item"
    style="width: 150px" onclick="return ReadButton_onclick()" /></p>
    <p><input id="UpdateButton" type="button" value="Update List Item"
    style="width: 150px" onclick="return UpdateButton_onclick()" /></p>
    <p><input id="DeleteButton" type="button" value="Delete List Item"
    style="width: 150px" onclick="return DeleteButton_onclick()" /></p>
    
  2. Add a JavaScript file called ListOperations.js file to your Visual Web Part node. Set the deployment type property to Element File. And add a Module node to the elements file to deploy the ListOperations.js file to the Assets library. Deploying this to the Assets library will allow you to deploy this as a sandboxed solution to both on-premise SharePoint sites and to SharePoint online sites.

  3. Add the following text to the Elements.xml file. You should need to add only the second Module node, as the first one was added by Visual Studio.

    <?xml version="1.0" encoding="utf-8"?>
    <Elements xmlns="https://schemas.microsoft.com/sharepoint/" >
      <Module Name="ListOperationsVisualWebPart" List="113" Url="_catalogs/wp">
        <File Path="ListOperationsVisualWebPart\ListOperationsVisualWebPart.webpart"
        Url="ListOperationsVisualWebPart.webpart" Type="GhostableInLibrary">
          <Property Name="Group" Value="Custom" />
        </File>
      </Module>
      <Module Name="jsFiles">
        <File Path="ListOperationsVisualWebPart\ListOperations.js"
          Url="SiteAssets/ListOperations.js" />
      </Module>
    </Elements>
    

Now that you have the Visual Web Part complete, you should deploy it and verify that you can add the Web Part to the site and that the ListOperations.js file is in the Assets library. You should see something similar to Figure 3. Now you are ready to focus on the actual JavaScript.

Figure 3. Customized site page

Customized site page

Creating lists

There are many ways to create lists in SharePoint. But sometimes you may need to create them dynamically from the client. Using the Client Object Model makes this very easy and straightforward. As you saw earlier, you need to get a reference to the ClientContext first. Next, you create a ListCreationInfo object to define the list and add it to the collection of lists in SharePoint. Finally, you define the actual field definitions for the columns of the list.

The most difficult part about creating a custom list is defining the fields. The fields are defined using Collaborative Markup Language (CAML). To see all the values, view Field Element on MSDN. Add the following code to your ListOperations.js file. This code will create a list called Airports that has two fields, AirportName and AirportCode.

var site;
var context;
function CreateList() {
  var listTitle = "Airports";
  var listDescription = "List of Airports";

  //Get the current client context
  context = SP.ClientContext.get_current();

  var site = context.get_web();

  //Create a new list
  var listCreationInfo = new SP.ListCreationInformation();
  listCreationInfo.set_templateType(SP.ListTemplateType.genericList);
  listCreationInfo.set_title(listTitle);
  listCreationInfo.set_description(listDescription);
  listCreationInfo.set_quickLaunchOption(SP.QuickLaunchOptions.on);

  var airportList = site.get_lists().add(listCreationInfo);

  //Create the fields
  var airportNameField = airportList.get_fields().addFieldAsXml(
    '<Field DisplayName=\'AirportName\' Type=\'Text\' />', true,
    SP.AddFieldOptions.defaultValue);
  var airportCodeField = airportList.get_fields().addFieldAsXml(
    '<Field DisplayName=\'AirportCode\' Type=\'Text\' />', true,
    SP.AddFieldOptions.defaultValue);

  context.load(airportNameField);
  context.load(airportCodeField);

  context.executeQueryAsync(CreateListSucceeded, CreateListFailed);
}

function CreateListSucceeded() {
  alert('List created.');
}

function CreateListFailed(sender, args) {
  alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}

You can also create predefined lists, such as an announcements list, without the need to define any fields. You can also define other field types, such as numbers, date and time, and Boolean. To see all the values, view Field Element on MSDN.

Adding list items

Now that you have created a custom list, the next thing to do is to add new records to the list. To create a list item, first create a new list item using the ListItemCreationInformation object, and then add it to the list using the addItem method. Next, you set the values for all the fields in the list item using the set_item method. Finally, you call the update method on the list item to flag it for updating before calling executeQueryAsync to commit the changes on the server. Add the following code to the ListOperations.js file.

function AddListItem() {
  var listTitle = "Airports";

  //Get the current client context
  context = SP.ClientContext.get_current();
  var airportList = context.get_web().get_lists().getByTitle(listTitle);

  //Create a new record
  var listItemCreationInformation = new SP.ListItemCreationInformation();
  var listItem = airportList.addItem(listItemCreationInformation);

  //Set the values
  listItem.set_item('AirportName', 'Seattle/Tacoma');
  listItem.set_item('AirportCode', 'SEA');
  listItem.set_item('Title', 'SEATAC');
  
  listItem.update();
  context.load(listItem);

  context.executeQueryAsync(AddListItemSucceeded, AddListItemFailed);
}

function AddListItemSucceeded() {
  alert('List Item Added.');
}

function AddListItemFailed(sender, args) {
  alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}

Reading list items

Reading lists follows the same pattern as other Client Object Model calls. First you get a reference to the client context and a reference to the list you want to read items from. In this case, you will read items from the Airports list that you created in the previous section. Next, you need to create a CAML query to specify which items you want returned.

Tip

You can learn more about Introduction to Collaborative Application Markup Language (CAML) on MSDN. Building CAML queries can be fairly complicated. It is recommended that you use a CAML query builder to help you build the correct query. A number of community CAML query tools are available on CodePlex. You can find the one that works best for you by searching CodePlex.

SharePoint provides a method, createAllItemsQuery, which returns a valid CAML string that returns all items. If you look at the createAllItemsQuery method in SP.Debug.js or debug the code, you will see the following CAML string that is returned.

<View Scope=\"RecursiveAll\">
  <Query></Query>
</View>

After you specify the CAML query, you load the list items query on the context, and then execute the query on the server asynchronously by calling executeQueryAsync.

Once the query returns from the server, in this case the ReadListItemsSucceeded method is called. Iterate over the returned items by getting a reference to the enumerator and calling the moveNext method in a while loop. On each iteration of the loop, you can get the current list item using the get_current method of the item. Finally, once you have a reference to the item, you can call the get_item method, passing in the string name of the field you want. Add the following code to the ListOperations.js fi le to read the list items.

function ReadListItem() {
  var listTitle = "Airports";

  //Get the current client context
  context = SP.ClientContext.get_current();
  var airportList = context.get_web().get_lists().getByTitle(listTitle);

  var camlQuery = SP.CamlQuery.createAllItemsQuery();

  this.listItems = airportList.getItems(camlQuery);

  context.load(listItems);

  context.executeQueryAsync(ReadListItemSucceeded, ReadListItemFailed);
}

function ReadListItemSucceeded(sender, args) {
  var itemsString = '';
  var enumerator = listItems.getEnumerator();

  while (enumerator.moveNext()) {
    var listItem = enumerator.get_current();
    itemsString += 'AirportName: ' + listItem.get_item('AirportName') +
' AirportCode: ' + listItem.get_id().toString() + '\n';
  }

  alert(itemsString);
}

function ReadListItemFailed(sender, args) {
  alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}

Updating list items

Updating list items is very straightforward. First, get a reference to the current context, and then get a reference to the list item that you want to update. This can be done in a number of ways. For example, you could use a CAML query to find the correct record or to iterate over a number of records. This example gets a reference to the record by using the record ID. Once you have the item, you can call the set_item method, passing in the name of the field and the updated value. You need to call the update method on the item to flag that it is to be updated. Finally, call the executeQueryAsync method to perform the update on the server. Add the following code to the ListOperations.js fi le to update the first record in the Airports list.

function UpdateListItem() {
  var listTitle = "Airports";

  //Get the current client context
  context = SP.ClientContext.get_current();
  var airportList = context.get_web().get_lists().getByTitle(listTitle);

  //Get the list item to update
  var listItem = airportList.getItemById(2);
  //Set the new property value
  listItem.set_item('AirportName', 'Seattle Tacoma Airport');
  listItem.update();

  context.executeQueryAsync(UpdateItemSucceeded, UpdateItemFailed);
}

function UpdateItemSucceeded() {
  alert('List Item Updated.');
}

function UpdateItemFailed(sender, args) {
  alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}

As a brief aside, one of the problems is verifying that you have the correct item ID. In this case I have only one record but I used the ID of 2. This is because I previously created a record and deleted it. Then when I created the record again, SharePoint assigned it the next available ID, which was 2. This makes it difficult to get the correct ID during development. One easy technique is to use the List Service to view the list data as a REST request. SharePoint will return the data as an OData Atom feed in which you can verify the fields and the records, including the item IDs. For example, if you browse to the Airports list using the List Service path at http://intranet.contoso.com/\_vti\_bin/listdata.svc/Airports. You will see the following Atom feed.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="http://intranet.contoso.com/_vti_bin/listdata.svc/"
xmlns:d="https://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="https://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Airports</title>
  <id>http://intranet.contoso.com/_vti_bin/listdata.svc/Airports/</id>
  <updated>2010-07-14T16:52:35Z</updated>
  <link rel="self" title="Airports" href="Airports" />
  <entry m:etag="W/&quot;2&quot;">
    <id>http://intranet.contoso.com/_vti_bin/listdata.svc/Airports(2)</id>
    <title type="text">SEATAC</title>
    <updated>2010-07-14T09:52:18-07:00</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="AirportsItem" href="Airports(2)" />
    <link rel="https://schemas.microsoft.com/ado/2007/08/dataservices/related/CreatedBy"
  type="application/atom+xml;type=entry" title="CreatedBy" href="Airports(2)/CreatedBy" />
    <link
  rel="https://schemas.microsoft.com/ado/2007/08/dataservices/related/ModifiedBy"
  type="application/atom+xml;type=entry" title="ModifiedBy"
  href="Airports(2)/ModifiedBy" />
    <link
  rel="https://schemas.microsoft.com/ado/2007/08/dataservices/related/Attachments"
  type="application/atom+xml;type=feed" title="Attachments"
  href="Airports(2)/Attachments" />
    <category term="Microsoft.SharePoint.DataService.AirportsItem"
  scheme="https://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:ContentTypeID>0x010041919BD85A48CA4B95F735848786C29C</d:ContentTypeID>
        <d:Title>SEATAC</d:Title>
        <d:AirportName>Seattle Tacoma Airport</d:AirportName>
        <d:AirportCode>SEA</d:AirportCode>
        <d:Id m:type="Edm.Int32">2</d:Id>
        <d:ContentType>Item</d:ContentType>
        <d:Modified m:type="Edm.DateTime">2010-07-14T09:52:18</d:Modified>
        <d:Created m:type="Edm.DateTime">2010-07-11T22:09:54</d:Created>
        <d:CreatedById m:type="Edm.Int32">16</d:CreatedById>
        <d:ModifiedById m:type="Edm.Int32">16</d:ModifiedById>
        <d:Owshiddenversion m:type="Edm.Int32">2</d:Owshiddenversion>
        <d:Version>1.0</d:Version>
        <d:Path>/Lists/Airports</d:Path>
      </m:properties>
    </content>
  </entry>
</feed>

You can see the ID in a couple of places, first in the href attribute in the link node and again in the Id field under the properties node. This query actually returns all the records in the list. (In this case, there is only one record.) To drill down on to a specific record, you could use a path with the item ID in parentheses at the end, http://intranet.contoso.com/\_vti\_bin/listdata.svc/Airports(2).

Deleting list items

Deleting records using the Client Object Model is very similar to updating records. First, get a reference to the current context. Next, get a reference to the list item that you want to update. Again, in this example I will get a reference to the record by using the record ID. Once you have a reference to the list item, call the deleteObject method to mark the record for deletion. Then call executeQueryAsync to perform the deletion of the record on the server. Add the following code to the ListOperation.js file.

function DeleteListItems() {
  var listTitle = "Airports";

  //get the current client context
  context = SP.ClientContext.get_current();
  var airportList = context.get_web().get_lists().getByTitle(listTitle);

  //get the list item to delete
  var listItem = airportList.getItemById(2);
  //delete the list item
  listItem.deleteObject();

  context.executeQueryAsync(DeleteItemSucceeded, DeleteItemFailed);
}

function DeleteItemSucceeded() {
  alert('List Item Deleted.');
}

function DeleteItemFailed(sender, args) {
  alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}

You have seen some of the most common methods for operating with list data in SharePoint. Although this doesn't cover everything that you can do with the Client Object Model, you should have enough information to understand the basic pattern that is used in all the operations. With this basic information, you will be able to understand the reference documentation and samples in the SharePoint SDK and on MSDN.

The next section looks briefly at how you can combine the power of the Client Object Model with the flexibility of jQuery.

Using jQuery with SharePoint 2010

jQuery is an open source JavaScript library that helps you build rich, dynamic, client-side applications. The power in jQuery comes from its simplicity and powerful query syntax. One of jQuery’s most powerful abilities is to quickly select various HTML DOM elements. Once you find the element or collection of elements, jQuery makes it easy to modify attributes and CSS for those elements. jQuery also supports extensibility through a rich plug-in model. In fact, a huge community of jQuery plug-ins is available. It is actually a core design point of jQuery to keep the core library small and provide most of the rich functionality via plug-ins. Although it is not possible to cover all aspects of jQuery in this chapter, there is one very important jQuery API with which SharePoint developers and designers should become familiar: the Ajax library. You learned about calling SharePoint from the client using the Client Object Model earlier in this chapter, but the Client Object Model doesn’t cover all SharePoint functionality. For example, Search is not covered by the Client Object Model and many others. The Client Object Model covers only APIs in the Microsoft.SharePoint.dll. This is where the jQuery Ajax library comes into play. Fortunately, SharePoint covers almost all its functionality with SOAP-based .asmx web services. The Ajax library makes it relatively easy to call these web services using jQuery from the client.

In this section, you will see how to call SharePoint web services using jQuery and dynamically display the results in a Content Editor Web Part (CEWP), without writing any server code.

Loading jQuery

You can download the jQuery library from the jQuery homepage. The current version as of thiswriting is 1.4.2. The jQuery library is a single fi le called jquery-1.4.2.js. There are actually two versions of this file.

  • jquery-1.4.2.js — A human-readable source version.

  • jquery-1.4.2.min.js — A minified and condensed version

I recommend using the source version for development and the minified version in production. Download the jquery-1.4.2.js file and put it in somewhere on your SharePoint site. Create a Scripts folder under the SiteAssets library to hold your JavaScript files. The path would be something similar to http://intranet.contoso.com/SiteAssets/Scripts/jquery-1.4.2.js.

To add the jQuery library, use the following script tag on your page.

<script src="/SiteAssets/Scripts/jquery-1.4.2.js" type="text/javascript"></script>

Another option is to use the jQuery library hosted on Microsoft’s content delivery network (CDN). The CDN geographically distributes the fi le around the world, making it faster for clients to download the file. With SharePoint on-premise installations, such as your intranet, this is not as important, but with SharePoint Online or SharePoint-based Internet sites, this will increase the perceived performance of your site. Add the following script tag to your page to use the Microsoft CDN to load the jQuery library.

<script src="https://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js"type="text/javascript"></script>

Ajax script loader

One thing that you need to be concerned with when using jQuery is that the jQuery library is loaded only once. There are a number of ways that you could do this, but this section mentions three ways and the various caveats associated with each method.

The first method is to just include the script tags, like you saw previously, directly to the page or, even better, to the master page. You would need to ensure that no other components also add a reference to the jQuery library. Here, the term "components" refer to anything that may inject code when the page renders, such as Web Parts. This is an acceptable approach if you control the entire page, but many times this is not possible due to the modular nature of SharePoint development.

The next approach is to use the ScriptLink control. The ScriptLink control ensures that the script is loaded only once and will also ensure that other dependencies have been loaded first. Add the following ScriptLink server-side tag to your page to load the jQuery library.

<SharePoint:ScriptLink ID= "SPScriptLink "
  runat= "server" Defer= "false "
  Localizable= "false " Name= "jquery-1.4.2.js ">
</SharePoint:ScriptLink>

The ScriptLink control requires that you put the jQuery library file in the LAYOUTS directory, C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS. This may not be possible if you have limited rights to the server, such as when you are creating sandboxed solutions. Also, even if the JavaScript library is in the LAYOUTS folder, the ScriptLink control is not allowed to run as a sandboxed solution. Therefore, I do not recommend this approach.

The third method, and the one that you should use, is to load jQuery using the Microsoft Ajax script loader, or another client-side script loader. One thing to be aware of is that the Microsoft ASP.NET Ajax library is now included as part of the Ajax Control Toolkit. This means that the ASP.NET Ajax library was split into server controls, which are now in the Ajax Control Toolkit, and client code, which is now done using jQuery. So, most of the functionality that was provided is now done in jQuery or through a jQuery plug-in, except the script loader. The Ajax library script loader has not been released yet for jQuery, so you will need to use the existing Start.js script loader library until it is released.

Download the Start.js library to your Site Assets library’s Script folder that you created earlier to hold your scripts. You can find the current script loader on Microsoft’s CDN at the following URL.

http://ajax .microsoft.com/ajax/beta/0910/Start.js.

You should also download the source version for development from the following URL.

https://ajax.microsoft.com/ajax/beta/0910/Start.debug.js.

Alternatively, you could load the Start.js library directly from the Microsoft CDN.

There are two steps to loading the jQuery library, or any of your custom JavaScript libraries. First, reference the script loader on your page using the following script tag.

<script src= "/SiteAssets/Scripts/Start.debug.js " type= "text/javascript "></script>

Or, if you are loading the library from the CDN, use the following script tag instead.

<script src= "https://ajax.microsoft.com/ajax/beta/0911/Start.js "type= "text/javascript"></script>

The second step is to reference the jQuery library or your own libraries using the Sys.loadScripts method, which is part of the Start.js library. The Sys.loadScripts method takes an array of scripts to load and a callback function to call when they have been loaded. Add the follow code to load the jQuery library.

<script type= "text/javascript ">
  Sys.loadScripts(["/SiteAssets/Scripts/jquery-1.4.2.js "], function() {
    alert("jQuery Loaded ");
  });
</script>

The Ajax Script Loader prevents the jQuery library from being loaded multiple times on the same page, even if you add many Web Parts that are using this code.

Calling SharePoint web services with jQuery

You have seen how to get SharePoint list data using the Client Object Model, but there are many types of SharePoint data that are not covered by the Client Object Model. The Client Object Model applies only to data in the Microsoft.SharePoint.dll, essentially functionality found in SharePoint Foundation only. To leverage other SharePoint data, such as profile data or search data, you will need to call the SharePoint web services. Calling these web services from the client using JavaScript has become much easier using the jQuery Ajax API. Let’s first take a quick look at how to retrieve list data, in this case the Announcements list, using jQuery. You could do this using the Client Object Model, but this example should serve as a bridge from doing it with the Client Object Model to doing it with jQuery.

jQuery in the Content Editor web part

To keep things simple and demonstrate another technique for using JavaScript on your pages, you will use the Content Editor Web Part (CEWP) to display a list of announcements. This example does not require Visual Studio; everything can be done using only a web browser.

To display a list of announcements by using JavaScript

  1. Start by adding a CEWP to the right column of your home page. You can find the CEWP in the Web Part gallery under the Media and Content category.

  2. Put the Web Part into edit mode by selecting Edit Web Part from the Web Part’s context menu. Click the link in the Web Part titled Click here to add new content.

  3. Next, edit the source HTML for the Web Part. Click the Editing Tools context-sensitive Format Text tab on the ribbon. In the Markup Ribbon group, select Edit HTML source from the HTML drop-down button. In the HTML source dialog, add the following code.

    <!--Load the Script Loader-->
    <script src= "/SiteAssets/Scripts/Start.debug.js" type= "text/javascript"></script>
    
    <!-- Load jQuery library-->
    <script type= "text/javascript">
      Sys.loadScripts(["/SiteAssets/Scripts/jquery-1.4.2.js"], function() {
      GetAnnouncements();
      });
    </script>
    <script type= "text/javascript">
      function GetAnnouncements() {
        var soapEnv = "<soap:Envelope
    xmlns:soap=’https://schemas.xmlsoap.org/soap/envelope/’> \
          <soap:Body> \
          <GetListItems xmlns=’https://schemas.microsoft.com/sharepoint/soap/’> \
            <listName>Announcements</listName> \
              <viewFields> \
                <ViewFields> \
                  <FieldRef Name=’Title’ /> \
                  <FieldRef Name=’Body’ /> \
                  <FieldRef Name=’Expires’ /> \
                </ViewFields> \
              </viewFields> \
            </GetListItems> \
          </soap:Body> \
        </soap:Envelope>";
      jQuery.ajax({
        url: "/_vti_bin/lists.asmx",
        type: "POST",
        dataType: "xml",
        data: soapEnv,
        complete: GetListItemsComplete,
        contentType: "text/xml; charset=\"utf-8\""
      });
    }
    function GetListItemsComplete(xData, status) {
      jQuery(xData.responseXML).find("z\\:row").each(function () {
        $("<li>" + $(this).attr("ows_Title") + "</li>").appendTo("#Announcements");
      });
    }
    </script>
    <ul id="Announcements"></ul>
    

The GetAnnouncements function builds the SOAP message and then uses the jQuery.ajax API to call the lists.asmx web service. The jQuery.ajax calls the GetListItemsCompleted callback method when the web service returns. The GetListItemsComplete method parses the XML data that returns from the lists.asmx web service. As it parses each record in the XML data, it appends a list item to the Announcements list using the appendTo function.

There are two key pieces to calling various SharePoint web services. The first is to understand the exact SOAP XML that is required to call the service, and the second is to understand the returned XML data and how to parse it to extract the exact values required. Although these change between the various services, the code pattern is the same for all services. Unfortunately, discovering how to format the SOAP message can be a challenge. Although MSDN documents the methods, it does not tell you the exact SOAP format or which parameters are optional. One of the easiest ways to discover the syntax is to create a console application in Visual Studio that calls the web service you are interested in calling from JavaScript. Then use the web debugging tool Fiddler to intercept and inspect the web service calls.

Summary

In this chapter you have seen how the new Client Object Model makes accessing SharePoint data as easy on the client as it is on the server. The Client Object Model covers the Microsoft.SharePoint.dll API on the client through a proxy object model that closely mirrors the server object model. The Client Object Model offers a very efficient calling pattern that not only gives you control over when and how often you call the server but also gives you control over the amount of data that is returned.

You have learned how you can leverage the power of jQuery to access SharePoint web services using the jQuery.Ajax API. You have also seen a number of different approaches to loading the jQuery library and other custom libraries. In the end, jQuery and the Client Object Model are complementary techniques to bring all the power of SharePoint to the client to create very rich applications that can run in both on-premise and online scenarios.

These two techniques for accessing SharePoint data from the client will enable you to create dynamic branding solutions based on data in SharePoint.

About the Authors

  • Randy Drisgill is a consultant with SharePoint911. He is a Microsoft MVP for SharePoint Server and the coauthor of Professional SharePoint 2007 Design.

  • John Ross is a consultant with SharePoint911 and a Microsoft MVP. He is an active member of the SharePoint community and a frequent guest speaker.

  • Jacob J. Sanford is a senior consultant for Cornerstone Software Services.

  • Paul Stubbs works at Microsoft and is a frequent speaker at Tech Ed and Dev Connections events about branding and SharePoint.