Question

JavaScript

For example, I have the following JavaScript code (Dojo 1.6 is already loaded):

dojo.require("dojo.io.script")

// PART I
var jsonpArgs = {
    url: "http://myapp.appspot.com/query",
    content: {
        id: "1234",
        name: "Juan",
        start_date: "2000-01-01",
        callback: "recover"
    }
};

// PART II
dojo.io.script.get(jsonpArgs).then(function(data) {
    console.log(data);
});

// PART III
function recover(data) {
    console.log(data);
}

Direct query from browser

I understand that my server will receive the query as though I typed the following into the address bar:

http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=recover

Expected response

If I directly queried my server using the browser address bar, I'll receive, in MIME type application/json and plaintext rendered in browser, something like this:

recover(
    {
        id: 1234,
        name: Juan,
        data: [
            ["2000-01-01", 1234],
            ["2000-01-02", 5678]
        ]
    }
);

Problem

Now, looking back at Part II of the JavaScript, I'd execute the JSONP request with dojo.io.script.get(jsonpArgs). This returns a Deferred object, which I can take advantage of by chaining .then after it. Note that I defined the handler for the .then event to output that captured data to the console.

However, all I get in the console is an Event. I tried to search its data tree, but I could not find the data I expected.

Question

  1. Where is the response for a JSONP request stored? How do I find it?
  2. My server (which I control) only outputs a plaintext rendering of the data requested, wrapped in the callback function (here specified as recover), and specifies a application/json MIME type. Is there anything else I need to set up on my server, so that the response data is captured by the Deferred object?

Attempted solution

I can actually recover the response by defining the callback function (in this case recover in Part III of the JavaScript). However, in the Dojo tutorials, they just recovered the data using the Deferred (and .then) framework. How do I do it using Dojo Deferreds?

Update (using the Twitter example from Dojo tutorial)

Take for example this script from the Dojo tutorial, Getting Jiggy With JSONP. I edited it to log data to the console.

dojo.require("dojo.io.script");
dojo.io.script.get({
    url: "http://search.twitter.com/search.json",
    callbackParamName: "callback",
    content: {q: "#dojo"}
}).then(function(data){
    //we're only interested in data.results, so strip it off and return it
    console.log(data); // I get an Object, not an Event, but no Twitter data when browsing the results property
    console.log(data.results) // I get an array of Objects
    return data.results;
});

For console.log(data), I get an Object, not an Event as illustrated by my case. Since the example implies that the data resides in data.results, I also try to browse this tree, but I don't see my expected data from Twitter. I'm at a loss.

For console.log(data.results), I get an array of Objects. If I query Twitter directly, this is what I'd get in plaintext. Each Object contains the usual tweet meta-data like username, time, user portrait, and the tweet itself. Easy enough.

This one hits me right on the head. The handler for the .then chain, an anonymous function, receives only one argument data. But why is it that the results property in console.log(data) and the returned object I get from console.log(data.results) are different?

Was it helpful?

Solution

I got it.

Manual callback implementation

function recover(data) {
    console.log(data);
}

var jsonpArgs = {
    url: "http://myapp.appspot.com/query",
    content: {
        id: "1234",
        name: "Juan",
        start_date: "2000-01-01",
        callback: "recover"
};

dojo.io.script.get(jsonpArgs);

This is the request that my server will receive:

http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=recover

In this case, I'll expect the following output from my server:

recover({
    id: 1234,
    name: Juan,
    data: [
        ["2000-01-01", 1234],
        ["2000-01-02", 5678]
    ]
});

Three things to note:

  1. Server will expect callback in the query URL string. callback is implemented as a property of jsonpArgs.
  2. Because I specified callback=recover, my server will attach recover( + the_data_I_need + ), returns the whole string to the browser, and browser will execute recover(the_data_I_need). This means...
  3. That I'll have to define, for example, function recover(one_argument_only) {doAnythingYouWantWith(one_argument_only)}

The problem with this approach is that I cannot take advantage of Deferred chaining using .then. For example:

dojo.io.script.get(jsonpArgs).then(function(response_from_server) {
    console.log(response_from_server);
})

This will give me an Event, with no trace of the expected response at all.


Taking advantage of Dojo's implementation of JSONP requests

var jsonpArgs = {
    url: "http://myapp.appspot.com/query",
    callbackParamName: "callback",
    content: {
        id: "1234",
        name: "Juan",
        start_date: "2000-01-01"
};

dojo.io.script.get(jsonpArgs);

This is the request that my server will receive:

http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=some_function_name_generated_by_dojo

In this case, I'll expect the following output from my server:

some_function_name_generated_by_dojo({
    id: 1234,
    name: Juan,
    data: [
        ["2000-01-01", 1234],
        ["2000-01-02", 5678]
    ]
});

Things to note:

  1. Note the property of jsonpArgs, callbackParamName. The value of this property must be the name of the variable (in the query URL string) expected by the server. If my server expects callbackfoo, then callbackParamName: "callbackfoo". In my case, my server expects the name callback, therefore callbackParamName: "callback".

  2. In the previous example, I specified in the query URL callback=recover and proceeded to implement function recover(...) {...}. This time, I do not need to worry about it. Dojo will insert its own preferred function callback=some_function_name_generated_by_dojo.

  3. I imagine some_function_name_generated_by_dojo to be defined as:

Definition:

function some_function_name_generated_by_dojo(response_from_server) {
    return response_from_server;
}

Of course the definition is not that simple, but the advantage of this approach is that I can take advantage of Dojo's Deferred framework. See the code below, which is identical to the previous example:

dojo.io.script.get(jsonpArgs).then(function(response_from_server) {
    console.log(response_from_server);
})

This will give me the exact data I need:

{
    id: 1234,
    name: Juan,
    data: [
        ["2000-01-01", 1234],
        ["2000-01-02", 5678]
    ]
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top