tags:

views:

496

answers:

2

My service returns the following JSON object, with the Content-Type header set to "application/javascript". It's wrapped in parens per instructions at json.org][2], but I've tried with and without parens. Without parens, it passes verification from jsonlint.

({"products": {"itemId": "0", "productId": "1234", "quantity": "4", "rank": "12", "subProductId": ""}, "txnId": "1"})

If I explicitly eval the response, as shown below, I have no problem:

var form = $('productListRequestForm');
form.request(
{
    onSuccess :
        function(response)
        {
            var json = eval(response.responseText);
            rebuildWishlistTable(json);
        },
    onFailure :
        function(response)
        {
            alert("AJAX request failed: " + response.responseText);
        }
});

However, if I rely on Prototype parsing the response and passing the parsed result as a second parameter to my function as below, that value is always null. According to the Prototype docs, this should work. Is there something that I'm missing, or something that they're missing?

   var form = $('productListRequestForm');
    form.request(
    {
        onSuccess : function(response, json)
            {
                rebuildWishlistTable(json);
            },
        onFailure :
            function(response)
            {
                alert("AJAX request failed: " + response.responseText);
            }
    });
A: 

Surround it with parenthesis

eval("({\"products\"": {\"itemId\": \"0\", \"productId\": \"1234\", \"quantity\": \"4\", \"rank\": \"12\", \"subProductId\": \"\"}, \"txnId\": \"1\"})")

That will work for you

Rodrigo
No, actually it doesn't. As I note in my post, the explicit eval works -- and as I also note, I wrap the JSON in parens to do that. The problem is that Prototype's auto-eval doesn't work, whether the JSON is wrapped in parens or not.
kdgregory
+1  A: 

It looks like a bug in Prototype.

At line 1497 in revision 1.6.1, there's the following code:

  var contentType = response.getHeader('Content-type');
  if (this.options.evalJS == 'force'
      || (this.options.evalJS && this.isSameOrigin() && contentType
      && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
    this.evalResponse();

Note that nothing is done with the return from evalResponse(). If we then go to the definition of that function:

  evalResponse: function() {
    try {
      return eval((this.transport.responseText || '').unfilterJSON());
    } catch (e) {
      this.dispatchException(e);
    }
  },


Posted a bug on the Prototype site, and it was closed with the comment that I had "several misunderstandings" regarding JSON, and shouldn't be using the bug reporting system to get help. Funny, I thought I was pointing out where they were throwing away a return value.

In case anyone else might have a similar situation, I'm editing my question to show the code that works and that doesn't work, and will be accepting this answer.

kdgregory