Problem with jQuery 1.7+ and SPServices

<UPDATE dateTime=”2012-12-04″>

This issue is resolved in v0.7.0+. See this post for more details, including the SPFilterNode function. </UPDATE>

<UPDATE dateTime=”2011-11-15T11:59GMT-1″>

Steve Workman has come up with a much improved way to do the selecting for things like z:row in general – it’s much faster, as Steve’s statistics show – and it also works with jQuery 1.7. I’ve added it to the latest alpha for v1.6.3 (which I will probably rename v0.7.0). More details to come, but this issue is going to be resolved in the upcoming release of SPServices.

</UPDATE>

Alert reader Dustin Meany pinged me yesterday with a brief email through this blog:

http://bugs.jquery.com/ticket/10377 — I think you should update the documentation for SPServices…

Ah, if the issue were only as small as his email. The ticket on the jQuery site talks about the fact that the notation that I’ve been recommending to parse through the results of a call to the Web Services, like:

$(xData.responseXML).find("[nodeName='z:row']").each(function() {
  // Do something
});

is no longer valid in jQuery 1.7.

I’ve confirmed in my main test pages that jQuery 1.7 no longer matches on any z:rows in calls to GetListItems. That breaks the majority of the “value added” functions in SPServices. The [nodeName='z:row'] notation has proved highly useful to ensure cross-browser compatibility, and that was the reason I’ve been recommending it in the first place. Because GetListItems uses the somewhat odd namespace of z:row, not all browsers react the same way. Of course GetListItems is the single most used Web Service operation with SPServices. Most of the other operations, which are used less often, do not use this type of namespace.

So the question is how we as a development community handle this. Based on the suggestion in the jQuery ticket, I could implement a function in SPServices itself that probably will solve the issues for the SPServices value-added functions. There are only ten calls in SPServices at the moment that use the [nodeName='z:row'] notation. However, there are thousands of you out there who have your own custom scripts written on top of SPServices that will break if you move to jQuery 1.7+.

The suggestion of switching to the .find("z\\:row, row") notation may work. I’ve quickly tested it with IE9, Chrome 15, Safari 5.1, and Firefox 7.0, all on my Windows 7 laptop. I don’t trust my cursory test, of course; there’s more work to do.

I hold no sway over the jQuery development team. They make their decisions without any knowledge of my little SPServices library or probably even SharePoint.

This, along with the XSL timeout issue I wrote about yesterday, may prove to be a big blow to those of us who choose to develop in SharePoint’s Middle Tier. As the standard bearer for this little movement, I can only do so much to make noise about how important and useful these development techniques are. When these types of roadblocks are put up, there’s little I can do to change things.

22 Comments

  1. That sucks, there must be a way around it. I don’t have much knowledge about how inheritance or extends works, but would it be possible in the spservices library add a function that inherits or extends the current .find() to work as before. As you say, I think there’s thousands of places this is called. Do you know where in the http://code.jquery.com/jquery-1.7.js the change that breaks it is made compared to http://code.jquery.com/jquery-1.6.4.js

    Reply
    • A bit ugly, but would something like this work http://jsbin.com/apete3


      var oldFind = $.fn.find;
      $.fn.find= function (selector) {
      selector.replace(/[nodeName='z:row']/g,"z\\:row, row");
      oldFind.call(selector.replace(/[nodeName='z:row']/g,"z\\:row, row"););//I know the replace is wrong, but using this principle might work?
      } ;

      Reply
      • Fredrik:

        Sorry, I wasn’t ignoring your suggestion, but I’ve been thinking about it. If I can make something like this work, I’d love to do it, but only if it would be bulletproof. I’ll probably play around with what you suggest, so thanks for it.

        M.

        Reply
    • A bit ugly, but would something like this work http://jsbin.com/apete3


      var oldFind = $.fn.find;
      $.fn.find= function (selector) {
      oldFind.call(selector.replace(/[nodeName='z:row']/g,"z\\:row, row"););//I know the replace is wrong, but using this principle might work?
      } ;

      Edit: forgot to remove one row above

      Reply
  2. Hi guys,

    I hadn’t seen this blog post when I wrote my article, but the .find(‘*’).filter(‘z:row’) method is monsterously quick when compared to the old method and works just as well with older jQuery versions.

    Cheers,
    Steve

    Reply
  3. All,

    Just wanted to let everyone know that the suggestion that Steve Workman gave works very well.

    Also, this issue seems to affect more then just the “z:row” element, but any element that SPServices is trying to find. I had just setup a permissions manager last week based on Marc’s 3 Nov post. Yesterday I discovered that it quit working. A few quick tweeks replacing every instance of ‘.find’ with ‘.find(‘*’).filter(‘ELEMENTNAME’) and I was back up.

    Hope this helps.

    Stephen

    Reply
      • Marc,

        As far as I can tell it was the update to jQuery 1.7. Our enterprise has jQuery referenced on the masterpage and the admin team update it as necessary.

        Last week the permission manager was working fine then yesterday it just alerted the “You must select a user” message, but the DDL wouldn’t populate. I did a check to see what version jQuery was loading and found that they had updated to 1.7. Luckily, I remembered this post and made the changes Steve suggested, adapting it as needed, and it worked like a champ.

        Stephen

        Reply
        • Stephen:

          There’s an example where an automatic upgrade isn’t such a great idea. There seem to be changes in every version of jQuery which make it clear that testing each time is really important. In several cases like this one, there have been backward compatibility issues. In any case, I’m gladd you sorted it out quickly.

          M.

          Reply
  4. Marc, I left a couple comments on Steve’s site.

    Now, here is a question for you: why would you want to do a filter based on the element name anyway?
    If you grab all the nodes with find(“*”), why not directly work with an attribute, for example ows_Title?

    Reply
    • Christophe:

      I think your example of ows_Title is orthogonal to the issue. The problem is that different browsers have issues with the .find(“z:row”) call. Chrome and Safari don’t find anything in the XML with that syntax. What I’ve been trying to do is come up with a syntax that will retrieve the right set of data across all browsers. The .find(“[nodeName=’z:row’]”) syntax worked really well for this pre-jQuery 1.7. In 1.7, that no longer works, and Steve has come up with the .find(“*”).filter(“z:row”) syntax, which not only seems to work across browsers, but is also performant.

      M.

      Reply
  5. Currently you are trying to fix a broken step.

    But actually the right question is not: how do I select all the z:row elements? It’s rather to step back a little and ask: what do I want to do with the xml returned from the call?

    What I am saying is that maybe you don’t need this step at all. Well, at least I know I don’t need it in my case.

    Reply
  6. sir i have a problem retrieving data. I have a document library with spaces how can I know the real name of that document library?

    Reply

Leave a Reply