<CharlieDigital/> Programming, Politics, and uhh…pineapples

25Jul/11Off

jQuery parsererror and WCF Data Services

Posted by Charles Chen

If you're using WCF Data Services (REST APIs for SharePoint, for example) and you're getting the mysterious "parsererror" error message from jQuery, chances are you'll need to modify your scripts according to this bug report.

The root of the error is the occurrence of single quotes within your JSON response.  This can be fixed by adding the following snippet of code before you make your AJAX calls:

$.ajaxSetup({
    // use custom converter to handle invalid json data
    // returned by WCF Data Service
    // fixes invalid escaped single quotes (\') in json data
    // e.g. { "foo": "bar\'tender" } --> { "foo": "bar'tender" }
    converters: {
        "text json": function( textValue ) {
            return jQuery.parseJSON( textValue.replace(/(^|[^\\])\\'/g, "$1'") );
        }
    }
});

Oddly, this error seemingly came out of nowhere for me; script was working fine one day and broken the next...

Luckily, the patch in this ticket seems to have fixed it for me.

Filed under: jQuery, SharePoint No Comments
15Jul/11Off

Chaining jQuery AJAX Calls (w/o Plugins)

Posted by Charles Chen

Here's the scenario: you need to make a series of AJAX calls to process a list of objects and each call is dependent on the results from the previous call.  How can we structure this elegantly in jQuery without having to write massive chains or script callbacks?

An example would be using an AJAX based API to create a hierarchy of nested folders.  Perhaps the user enters a string like "/path1/path2/path3" and multiple calls are needed to create "/path1", then /path1/path2," then "/path1/path2/path3".

My friend John Peterson brought up jQuery deferred to me today and it clicked and my life is better for it.

Here's an example:

var parts = ["path1","path2","path3"]; // Output from string.split()
var chain = $.Deferred(); // Create the root of the chain.
var promise; // Placeholder for the promise

// Build the chain
for(var i = 0; i < parts.length; i++)
{
    if(i == 0) promise = chain;

    // Pipe the response to the "next" function
    promise = promise.pipe(function(response)
    {
        var part = this.shift(); // Get the current part

        var root = "";

        if(response)
        {
            root = response.newPath;
        }

        return $.ajax // MUST call return here.
        ({
           type: "GET",
           url: "filemanager/create/" + root + part,
           context: this
        });
    })
}

promise.done(function(response){
    // This handles the response from the final AJAX call
});

chain.resolveWith(parts); // Execute the chain

The general idea is that we start with a chain and "pipe" the output from each step to the next.  When I execute the chain, I pass in the array as the argument on line 35.

This is necessary because referring to part[i] inside the function declared on line 11 will always yield "part3" .  To work around this, we pass in the whole array of parts as the context to the chain.  It becomes the "this" reference and we simply shift() a value off of the array to get the "current" item.

To pass the array to the next function in the chain, we simply set the context of the AJAX call to the "this" reference.  Now, in the next handler in the chain, the "response" is the output of the previous AJAX call and the "this" reference is the "current" item in the array.

Of course, the final call -- if you want to handle it -- can be added to the chain using done() instead of pipe().

It's a brilliant way of chaining multiple jQuery AJAX calls in a much more coherent manner!

Filed under: Awesome, Dev, jQuery No Comments