Single-Page Applications (SPAs) in SharePoint Using SPServices – Part 3 – GetListItemChanges

In building a Single Page Application (SPA), we’ll usually want to keep the data we’re displaying up to date. You can probably think of many examples where you see this on the Web, but newsfeeds are a prime example. While we’re sitting on the page, we see newly posted content pop up, usually on the top of the feed. To do this, we can simply set up a call to run at fixed intervals using JavaScript’s timing functions setTimeout() or setInterval() to pull back the data.

If the content we want is in a list, it’s “expensive” to request all of the items at each interval. Instead, it’s much better to either cache the items if they rarely change – as is available in SPServices 0.7.2+, though the approach in 2013.01 is much improved – or to request only those items which have changed since the last request.

There are two operations which can help with this: GetListItemChanges and GetListItemChangesWithToken.

[important]GetListItemChanges and GetListItemChangesWithToken do not work in versions of SPServices before 2013.02.[/important]

In this post, let’s take a look at the GetListItemChanges operation.

GetListItemChanges

GetListItemChanges retrieves changes to the list since a specified date/time. The parameters are similar to those for GetListItems, with a few additions:

[webURL]

See the GetListItems post in this series.

listName

See the GetListItems post in this series.

viewFields

See the GetListItems post in this series.

since

A date/time specified in Coordinated Universal Time (UTC) ISO8601 format. What that means is that the date/time has to look like “2013-06-30T15:29:43Z”. That’s “YYYY-MM-DDThh:mm:ssZ”. The “Z” means “Zulu” time, or GMT. You can also provide time offsets, like “2013-06-30T15:29:43-05:00″ for Eastern (US) Time.

Because I’m a nice guy, I have a function in SPServices called SPConvertDateToISO to convert JavaScript date/time objects to the ISO8601 format.

contains

The contains parameter is much like the CAMLQuery parameter in GetListItems, but a little simpler. For instance, you may only be interested in list changes where the current user is the Author, in which case you’d pass:

contains: "<Eq><FieldRef Name='Author'/><Value Type='Integer'><UserID/></Value></Eq>",

If you don’t pass anything for contains, you’ll get back all of the changes since since.

Because the GetListItemChanges operation retrieves only changes in the list, the requests will return very slim results in all but the most active lists. However, the operation will prove valuable in our SPA development because it will allow us to keep our display current for the user with a minimum of fuss unless there have been changes to the underlying data.

GetListItemChanges Returns

When Paul Tavares (@paul_tavares) pointed out the GetListItemChangesWithToken operation a while back, I recalled that I never could get it running properly in my test environment back when I first wrapped it in SPServices. I wrote it off to either my own ineptitude or simply a bug on the Microsoft side (that wouldn’t be a first). At the time, it didn’t seem as though the operation offered enough benefit to chase it down any further.

I was wrong on several counts, of course. The bit about my ineptitude was the one part I was right about. When I wrapped the operation, I accepted two things about it that the documentation told me:

changeToken

A string that contains the change token for the request. For a description of the format that is used in this string, see Overview: Change Tokens, Object Types, and Change Types. If null is passed, all items in the list are returned.

contains

A Contains element that defines custom filtering for the query and that can be assigned to a System.Xml.XmlNode object, as in the following example.

<Contains>
   <FieldRef Name="Status"/>
   <Value Type="Text">Complete</Value>
</Contains>

This parameter can contain null.

The italicized, maroon parts were the issue. While it’s probably possible to pass null on the server side, there’s no such analogous value on the client that we can pass. Since everything we pass is text, generally an empty string will work in those operations where null is allowable. But not in this case.

This means that in all versions of SPServices until the alpha I’ve currently got posted, the operations GetListItemsChanges and GetListItemsChangesWithToken won’t work, no matter how hard you try. That’s because I passed empty strings for the elements above, which just throws an error.

All that said, GetListItemsChanges returns XML that looks the same as what GetListItems gives us.

<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/"
   TimeStamp="2013-11-14T16:30:36Z">
   <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’s one subtle difference. Can you spot it? GetListItemChanges gives us one additional piece of data with the results, and that’s the TimeStamp value. This date/time value tells us when we requested the data, so we can use that value to inform the user when the data was last updated, should we want to.

Processing GetListItems Results

Processing the results from GetListItemChanges is just about the same as with GetListItems.

var out = "<ul>";
$().SPServices({
  operation: "GetListItemChanges",
  since: "2013-11-14T11:00:00-5:00",
  async: false,
  listName: "Announcements",
  CAMLRowLimit: 0,
  CAMLViewFields: "<ViewFields><FieldRef Name='Title' /></ViewFields>",
  completefunc: function (xData, Status) {
    var timeStamp = $(xData.responseXML).SPFilterNode("listitems").attr("TimeStamp");
    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 GetListItemChanges to get all of the items in the Announcements list which have changed since 11am this morning in Boston.

Conclusion

GetListItemChanges is a great addition to our toolkit because it allows us to make requests for items in a list that have changed since a time we specify. While we could accomplish something similar with GetListItems by passing in a filter for Modified in the CAMLQuery, GetListItemChanges is built for exactly what we need, and I would hope that it is therefore more efficient on the server side.
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.

SharePoint Saturday Chicago 2013 Follow Up

I can honestly say that I’m sure that everyone enjoyed SharePoint Saturday Chicago yesterday. From the location at the Hard Rock Chicago to the fantastic speaker line up (I snuck in) to the overall convivial atmosphere, it was an event to remember. Kudos go out to Kris Wagner (@SharePointKris), Doug Hemminger (@DougHemminger), Chris Geier (@chrisgeier), and Bryan Gulley (@UXJester) for all the hard work they put in to make it a special event. I know many others worked long and hard, too, but those names are not in my old brain. Thanks to all of you!

IMG_6503[1]Dux Sy (@meetdux) kicked things off with his keynote “Lead the Enterprise Social Revolution”, where we learned that #shifthappens. Yuo can see Dux’s entire presentation in a live recording on UStream or review or download his slides on SlideShare.

There were some other sessions.

My session was about “Designing with SharePoint 2013″, wherein I attempted to describe some of the high level goals one should have in designing for the platform as well as to demonstrate the great capabilities in the new Design Manager.

We had a standing room only crowd in the truly small Firebird room, so we all got a bit more chummy by rubbing elbows and knees. I was able to assist my pal Marcy Kellar (@marcykellar) in welcoming SharePoint newcomer Cara Gail (@caragail) from Indianapolis.

This session will introduce you to the possibilities of design and customization in SharePoint 2013. Tour the newest interface features, learn best practices, and discover exciting new ways to interact with your SharePoint 2013 environment.

While we can still implement designs in SharePoint 2013 the “old way” we’re used to, there are new capabilities that can make the process easier for both designers who are very familiar with SharePoint and those designers who have never worked with SharePoint.

We’ll look at the new Design Manager capabilities and learn how to create and integrate Master pages, Display Templates, and Page Layouts.  Not only does the Design Manager make it easier to create new designs for SharePoint from scratch, it can also help you manage your existing designs after an upgrade. The Design Manager even allows designers to use the tools they know and love like Dreamweaver, Photoshop, or any other HTML editor.

I didn’t have any fancy-schmancy live video recording going on like Dux did, but you can see my slides on SlideShare.

IMG_6508[1]After the formalities and a brief SharePint, a bunch of speakers and a few attendees decided to have dinner at The Signature Room at the 95th® (“The Restaurant Chicago Looks Up To”, don’t you know?) You can see the crew in this photo: Lori Gowen (@LoriGowin), Doug Hemminger (one of our most excellent hosts for the event), Kim Frehe (@KimFrehe), Brittany Kwait (@BrittanyKwait), Michelle Caldwell (@shellecaldwell), Chris Johnson (@LoungeFlyZ), Ruven Gotz (@ruveng), and another SharePoint community newcomer Dan Moore. (Dan: Isn’t the SharePoint community awesome? How was the duck hash this morning?)

IMG_6541[1]Finally, I had a little time to walk around this morning and made it to see a few things. Most impressive was “The Bean”, aka “Cloud City”. I’ve wanted to see this sculpture ever since it was first installed, and it did impress. (I really only went to see it to make Dave Coleman (@davecoleman146) jealous, and it worked.)

Setting a Conditional Breakpoint in Firefox with Firebug

Every once in a while I click randomly on something and realize that I’ve been an idiot. OK, sometimes it doesn’t require clicking on anything.

First off, if you’re working on client side code and you aren’t using Firefox with the Firebug add on, you should be. It gives you all the debugging capability that you need to win. (Some others swear by Chrome, but I’ve been developing with Firefox for a long time.)

Firebug

Everyone else has probably known this for millennia, but I just figured out today that I can set a conditional breakpoint in Firebug. If you right click on a line where you’ve set a breakpoint (this was my random click), you get a syntax menu that looks something like this:

Firebug Breakpoint Context Menu

By selecting Edit Breakpoint Condition… you can add any valid JavaScript condition. Here’s one I used to break when I was processing row 55 in a loop:

Firebug Conditional BreakpointSetting a condition like this is really useful, especially when you know that item 55 out of 4645 is causing an error and you just want to step through your script for that item.

There’s more to conditional breakpoints in Firebug [I know now], as you can read in the Firebug Tip: Conditional Breakpoints post on the Firebug blog.

Perhaps because I’m old school, while I’ve truly wanted to be able to set conditional breakpoints like this I’ve simply changed my indices or put in conditional debugging statements. I’ve gotten by just fine, but I’m going to be a lot more efficient now. If you didn’t know about this little trick, then hopefully you’ll be more efficient now, too.

Or maybe I’m just an idiot.

SPServices Passes 100,000 Total Downloads

Here are some numbers for the meaningless-but-fun-statistics bin. Codeplex collects a bunch of numbers for me, so I can preserve them here.

Yesterday, Sunday, October 27th, 2013, SPServices crossed the 100,000 total downloads threshold. I posted the first version of SPServices (SPServices 0.2.3) on Codeplex on Aug 19th, 2009 as an alpha. That means it’s taken 4 years, 2 months, and 9 days – that’s 1531 days – to reach 100,000 downloads. That’s over 65 downloads per day!

SPServices 100,000 DownloadsDuring that same period, SPServices has also had almost 3,000,000 page views – 2,945,339 to be exact. I like to think that this number is a testament to the quality of the documentation.

SPServices 3,000,000 Page ViewsThere have been over 3/4 million visits to the Codeplex site.

SPServices 3/4 Million VisitsIt’s been a fun 4 years, 2 months, and 9 days working on and supporting SPServices. I doubt it’s got another 4 years in it, but I look forward to many more months and downloads to come.

Yes, I do make it up in volume.

Should You Use the ‘var $this = $(this);’ Syntax in jQuery?

The other day I tweeted that I

May succumb to this this syntax: var $this = $(this);*

May succumb to this this syntax

Click image to see original Facebook thread

Because I use Hootsuite and it’s a simple button push, I also posted it to Facebook. George Winters saw it there and wondered what I meant.

I was referring to a common jQuery coding practice.

var $this = $(this);

In the past, my answer on whether this practice was useful or necessary has always been “no”. I tend to use the convention of naming my variables like this:

var thisTermId = $(this).attr("a9");

and I’ve felt that this was enough “this” stuff. (Yes, this post is going to have a lot of this this stuff in it.)

So why do we care?

In this example, I’m parsing out the results form a call to the TaxonomyClientService GetChildTermsInTerm operation. (More on this in a later post.) We get back a text representation of the XML which ends up looking like this after some conversions:

<TermStore>
  <T a9="988b1b74-3b87-4f40-a6ee-066e592fbe89" a21="false" a61="0" a1000="227">
    <LS>
      <TL a32="Cereal" a31="true"/>
      <TL a32="Breakfast Treat" a31="false"/>
      <TL a32="Grains" a31="false"/>
      <TL a32="Bowl of breakfast" a31="false"/>
    </LS>
    <DS/>
    <TMS>
      <TM a24="d8110aa1-d8c2-4e0f-8a99-7e82db8a32dd" a12="Breakfast Foods" a40="" a17="true" a67="" a45="988b1b74-3b87-4f40-a6ee-066e592fbe89"/>
    </TMS>
  </T>
  <T a9="b793fd58-45b7-4540-9098-140815864900" a21="false" a61="0" a1000="291">
    <LS>
      <TL a32="Bacon" a31="true"/>
      <TL a32="Manna" a31="false"/>
      <TL a32="Rackley's Favorite Food" a31="false"/>
    </LS>
    <DS/>
    <TMS>
      <TM a24="d8110aa1-d8c2-4e0f-8a99-7e82db8a32dd" a12="Breakfast Foods" a40="" a17="true" a67="" a45="b793fd58-45b7-4540-9098-140815864900"/>
    </TMS>
  </T>
  ...
</TermStore>

The data is pretty well organized, but I need to get it into an array so that I can use it in my application. To do this, I use jQuery selectors and .each() logic to iterate through the data, much like C# folks use enumerators.

In jQuery, when you use a selector, you can refer to the matches with $(this). Here’s a simplified version of the code I’m using:

$($termsXML).find("T").each(function() {
  var thisTermId = $(this).attr("a9");
  var thisTermName = $(this).find("TL[a31='true']").attr("a32");
  ...
});

In the example, I’m finding all of the elements (terms) in the $termsXML jQuery object and then parsing out two of the attributes inside them. I’m using $(this) in two different places (and in the actual code, many more places). Many JavaScript developers would do this instead:

$($termsXML).find("T").each(function() {
  var $thisTerm = $(this);
  var thisTermId = $thisTerm.attr("a9");
  var thisTermName = $thisTerm.find("TL[a31='true']").attr("a32");
  ...
});

There are a few benefits:

  • $(this) is only evaluated once (minor efficiency)
  • You can use a more descriptive name for $(this). I’m using $thisTerm above because it’s a taxonomy term.
  • By preceding the variable name with the $ sign, you’re reminding yourself that it’s a jQuery variable, not just a plain old JavaScript variable.

This all is really up to you. JSLint and JSHint don’t care whether you do this or not, but your code may be more readable over time. Whatever conventions you decide to follow, the more important thing is that you remain consistent over time. I’ve not used the $this syntax before and if I start doing it selectively in SPServices, for instance, I’ll have a tougher time maintaining it.


* I love playing with words like that. Check out this great picture I saw on Facebook the other day. But I digress…ship-shipping ship