Single-Page Applications (SPAs) in SharePoint Using SPServices – Part 2 – GetListItems

As I mentioned in the first part of the series, we have several workhorse operations at our disposal in the SOAP Web Services with which we can build our Single-page Applications (SPAs). (Of course, which API you use is somewhat unimportant. All of the techniques here should work using REST or CSOM, too. I’m just choosing to focus on SPServices and the SOAP Web Services.) There are many more SOAP operations that can prove useful, of course, but at first we’ll focus on the key set below which help us get data out of or push data into SharePoint lists and libraries.

While each of these operations is documented on the SPServices Codeplex site, I’m going to repeat some of that documentation here for anyone who is learning about them for the first time.

[important]GetListItemChanges and GetListItemChangesWithToken do not work in versions of SPServices before 2013.02. I’ll talk more about this in the next part in the series.[/important]

First, let’s review the primary workhorse operation, GetListItems.

GetListItems

GetListItems is generally the first operation that people try out when they start working with SPServices. It does exactly what its name implies: it enables you to get items from a list. In this sense, lists and libraries are the same thing. All useful SharePoint content that is available through the UI is stored in lists, even much of the configuration data that we set up. Document Libraries are lists. Publishing pages are are in lists, too. They just happen to be in a special flavor of Document Library, which is a list, called Pages.

GetListItems takes a set of parameters that makes it extremely powerful. If you can imagine a way to pull data from a list, you can probably do it, or get very close and then process the data client side into the form you need.

What this operation doesn’t do for you is any sort of aggregation. Once you have the data client side, you can work on aggregation from there in your code. This means that it’s important to carefully think about the data volume you might be pulling from the list and whether munging through it on the client side is a good idea or not based on what you need to accomplish.

The available parameters are listed below.

[webURL]

If you’d like to get content from a list in a different site than the current one (a different context), this parameter is what you need. You can specify any valid path. I recommend relative paths wherever possible so that you don’t run into cross site scripting issues moving from one environment to another.

listName

You must specify a listName at the bare minimum, as this tells the Web service where to get the content for you. You can provide either the list’s GUID (“{3bf9d2f3-78ec-4e92-a4c0-7c5f7ed51755}”) or the list’s name (“Announcements”). Note also that if you use the GUID, you do not need to specify the webURL if the list is in another site.

viewName

By default, GetListItems retrieves the items which are displayed in the default view for the list or library. If you specify a view’s GUID for the viewName parameter, you can retrieve the items shown in any existing view. In most cases, I’d recommend specifying what you’d like to retrieve using the CAML parameters below, as views can be easily changed through the UI and you may not retrieve what you’d expect.

CAMLViewFields

In the CAMLViewFields, you specify which list columns you’d like to retrieve. By default, you’ll get the columns defined in the default view. In many cases, you’ll want to request different columns, and you should also request as few columns as possible in order to reduce the number of bytes coming across the wire.

As an example, this is what you would specify in the CAMLViewFields to retrieve the Title and Created By (Author) columns.

CAMLViewFields: "<ViewFields><FieldRef Name='Title' /><FieldRef Name='Author' /></ViewFields>",

The column names should be the InternalNames for the columns, which might look like “My_x0020_Column”, as special characters like spaces are encoded. In this case, the space becomes “_x0020_” because a space is ASCII character 20 (hexadecimal). See http://www.asciitable.com/ for more info.

The easiest way to identify the InternalName for a column is to go to the List [or Library] Settings, click on the column name, and look on the end of the URL, which will end with something like this in SharePoint 2007:

/_layouts/FldEditEx.aspx?List={37920121-19B2-4C77-92FF-8B3E07853114}&Field=Sales_x0020_Rep

or this in SharePoint 2013:

/_layouts/15/FldEdit.aspx?List={F3641DF3-80A2-4BBA-A753-E6BFB3FD98E4}&Field=ImageCreateDate

Your column’s InternalName is at the end of the URL after “Field=”.

Note that regardless what you specify in the CAMLViewFields, you will get some additional columns even though you don’t want them, including the item’s ID.

CAMLQuery

In CAMLQuery, you specify any filters or sorting you’d like to apply to the results. Yes, it’s CAML, and no, most people don’t like CAML much. I find it great because it’s an easy language to build up programmatically in SPServices, but that’s me.

The syntax for the CAMLQuerycan be complicated, but CAML is well-documented. Here’s a simple example:

CAMLQuery: "<Query><Where><Contains><FieldRef Name='Title'/><Value Type='Text'>and</Value></Contains></Where><OrderBy><FieldRef Name='Title'/></OrderBy></Query>",

This CAMLQuery will retrieve items which contain “and” in their Title and sort those items by Title.

CAMLRowLimit

CAMLRowLimit allows you to specify the number of items you would like to retrieve. You can specify any positive integer.

CAMLRowLimit: 10,

CAMLQueryOptions

There are a number of CAMLQueryOptions, some of which work more as advertised than others. I’ll leave it as an exercise for the reader to read up on the available options in the MSDN documentation. Note that the options listed on the GetListItems page are not complete; see the GetListItemChangesSinceToken documentation for a more complete list.

Notes for GetListItems

When I first started building SPServices, I named the parameters [CAMLViewFields, CAMLQuery, CAMLRowLimit, CAMLQueryOptions] differently than the actual parameter names, which are [viewFields, query, rowLimit, queryOptions]. I’ve since set it up inside SPServices so that you can use either name, but most people continue to use the naming I came up with originally with the CAML prefix.

If you specify any of the parameters [CAMLViewFields, CAMLQuery, CAMLRowLimit, CAMLQueryOptions] explicitly, you will override the default view. One trick I use frequently to force the override is to just pass 0 for the CAMLRowLimit, which tells the GetListItems to return all items. I’ve seen quite a few other people pass in a CAMLQuery like:

<Query><Where><Gt><FieldRef Name='ID'/><Value Type='Counter'>0</Value></Gt></Where></Query>

This says to retrieve all items where the ID is greater than zero, which is true for all items since IDs start at one and increase from there. That seems like more code than “0” to me, though.

GetListItems supports paging, though I rarely take advantage of it. I find that it often makes more sense to request all of the relevant items and do the paging on the client side. This makes sense because the more “expensive” action is the request for data from the server. However, if you are requesting items from large lists and may not need the majority of them, be sure to use tight filters or paging for efficiency.

GetListItems Returns

The GetListItems operation returns XML, as do all of the SOAP Web Services operations. The results take the following form:

<listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
   xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
   xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"
   xmlns="http://schemas.microsoft.com/sharepoint/soap/">
   <rs:data ItemCount="4">
      <z:row ows_Number_Field="6555.00000000000"
         ows_Created="2003-06-18T03:41:09Z"
         ows_ID="3" ows_owshiddenversion="3" />
      <z:row ows_Number_Field="78905456.0000000"
         ows_Created="2003-06-18T17:15:58Z"
         ows_ID="4" ows_owshiddenversion="2" />
         ...
   </rs:data>
</listitems>

There are some important things to note about the results:

  • There is an rs:data element which contains an ItemCount element, telling us how many items have been returned
  • Each of the returned items is contained in a z:row element
  • Each item’s columns are provided as attributes on the z:row elements
  • All column names are preceded with the prefix “ows_”
  • All values are text (everything in both directions is text)

Processing GetListItems Results

Processing the results from GetListItems is fairly straightforward, but there are a few nuances. Assuming you have a container in the page with its id set to announcementsContainer, the following code will create an unordered list (bullets) showing the titles of each announcement in the Announcements list.

var out = "<ul>";
$().SPServices({
  operation: "GetListItems",
  async: false,
  listName: "Announcements",
  CAMLRowLimit: 0,
  CAMLViewFields: "<ViewFields><FieldRef Name='Title' /></ViewFields>",
  completefunc: function (xData, Status) {
    var itemCount = $(xData.responseXML).SPFilterNode("rs:data").attr("ItemCount");
    $(xData.responseXML).SPFilterNode("z:row").each(function() {
      out += "<li>" + $(this).attr("ows_Title") + "</li>";
    });
    out += "</ul>";
    $("#announcementsContainer").html(out);
  }
});

Here I’m making the call to GetListItems to get all of the items in the Announcements list. (By passing a CAMLRowLimit of zero, I’m requesting all items.) When the results come back, I’m iterating through all of the items (the z:row elements), building up my out string to contain the list bullets. Finally, I set the innerHTML of the announcementsContainer to what I’ve built up in the out variable.

Conclusion

GetListItems is a workhorse, all right, but we need more for our SPA work. In the next three parts of the series, I’ll introduce its siblings: GetListItemChanges, GetListItemChangesWithToken, and UpdateListItems. These four operations together will help us to build a highly interactive SPA and provide valuable functionality for our users.

Series Navigation<< Single-Page Applications (SPAs) in SharePoint Using SPServices – Part 1 – IntroductionSingle-Page Applications (SPAs) in SharePoint Using SPServices – Part 3 – GetListItemChanges >>

Similar Posts

10 Comments

  1. Marc,
    Great setup… I see the path you are taking… Detail out the building blocks to putting it all together…
    In my working with the API, I have found that GetListItems, UpdateListItems and GetList are the operations I use and depend upon the most. I recently found the benefits of GetListItemChangesSinceToken which play extremely well with the need to maintain the UI in sync with other user’s updates to the data. It (GetListItemChangesSinceToken) may be on its way to become my new workhorse for retrieving data.

    1. Paul:

      Indeed, and I wouldn’t have started this series if you hadn’t made me look at GetListItemChanges and GetListItemChangesSinceToken again. I’ve done SPA-like things with just GetListItems in the past, but GetListItemChangesSinceToken looks to make that go much more smoothly and more efficiently.

      I’m still trying to decide on the example for this. I keep coming back to a help desk ticketing system, but that’s so overdone.

      M.

    1. Matt:

      Exercise for the reader? (Kidding.) Yes, I suppose I did. My goal in this post was to explain how GetListItems works more than talk about what you can do with the results. In a later post, I’ll show how you can use those results in your SPA.

      M.

  2. Hey Marc,

    Thanks for your article. My goal is to view certain fields in the data returned that are not even in the view I specified. How can I do this, aside from creating a new view for my list with the columns that I want to see? I tried giving column names that are not in the view specified and could not get them in the data returned.

    1. Sreejitha:

      You can use the CAMLViewFields option to specify columns you’d like to retrieve. Generally, we want to be as specific as possible so that we control how much data comes over the wire. Also, by specifying an option like CAMLViewFields or CAMLQuery, we disassociate our call from the default view. This is good, since someone can change the view, breaking our code.

      M.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.