PDA

View Full Version : Proper way to consume external JSONP data from a Panel



rockinthesixstring
13 Jun 2011, 3:45 PM
I've got a panel that is supposed to be consuming JSONP from an external web service.

app/WebService.js



var WebService = {
Url: 'http://rpc.infinitas.ws/',
Vimeo: {
Read: 'Vimeo/Read',
Hit: 'Vimeo/Hit'
},
Contact: {
Communicate: 'Contact/Communicate',
Contact: 'Contact/Contact',
Hit: 'Contact/Hit'
}
};


models/VimeoModel.js


rpc.models.VimeoModel = Ext.regModel('rpc.models.VimeoModel', {
fields: [
{name: 'id', type: 'int'},
{name: 'title', type: 'string'}
]
});
views/VideoView.js


rpc.views.VideoView = new Ext.Panel({
id: 'VideoView',
title: "Videos",
tpl: VimeoTemplate,
iconCls: "tv",
dockedItems: [{ xtype: "toolbar", title: "Videos"}],
store: 'rpc.stores.VimeoStore'
});
stores/VimeoStore.js


rpc.stores.VimeoStore = new Ext.data.Store({
id: 'VimeoStore',
model: 'rpc.models.VimeoModel',
proxy: {
type: 'scripttag',
url: WebService.Url + WebService.Vimeo.Read,
reader: {
type: 'jsonp'
}
},
autoLoad: true
});
templates/VimeoTemplate.js


var VimeoTemplate = new Ext.XTemplate([
'<tpl for=".">',
'<div>',
'{title}',
'</div>',
'</tpl>'
]);
Unfortunately when the page loads, there is no data being populated into the VideoView.
The WebService is located at http://rpc.infinitas.ws/Vimeo/Read?_dc=stcCallback1001
It's returning a JSONP response


stcCallback1001([{"id":25036464,"title":"Power of A Surrendered Li..."},{"id":25036610,"title":"Child Dedication June 2011"},{"id":24734142,"title":"Power of A Surrendered Li..."},{"id":24884833,"title":"Finance Update June 2011"},{"id":24587711,"title":"Papua, Indonesia Sharing ..."},{"id":24232427,"title":"ICHTHUS: Coming King"},{"id":23868560,"title":"ICHTHUS: Healer"},{"id":23486615,"title":"ICHTHUS: Sanctifier"},{"id":23211649,"title":"ICHTHUS: Saviour"},{"id":23867961,"title":"Elder Announcement re: Br..."},{"id":22998163,"title":"Triumph of Grace: Risen L..."},{"id":23687914,"title":"Triumph of Grace: Reignin..."},{"id":23692076,"title":"KINGDOM now: For Thine Is..."},{"id":23694183,"title":"KINGDOM now: Deliver Us F..."}]);stcCallback1001([{"id":25036464,"title":"Power of A Surrendered Li..."},{"id":25036610,"title":"Child Dedication June 2011"},{"id":24734142,"title":"Power of A Surrendered Li..."},{"id":24884833,"title":"Finance Update June 2011"},{"id":24587711,"title":"Papua, Indonesia Sharing ..."},{"id":24232427,"title":"ICHTHUS: Coming King"},{"id":23868560,"title":"ICHTHUS: Healer"},{"id":23486615,"title":"ICHTHUS: Sanctifier"},{"id":23211649,"title":"ICHTHUS: Saviour"},{"id":23867961,"title":"Elder Announcement re: Br..."},{"id":22998163,"title":"Triumph of Grace: Risen L..."},{"id":23687914,"title":"Triumph of Grace: Reignin..."},{"id":23692076,"title":"KINGDOM now: For Thine Is..."},{"id":23694183,"title":"KINGDOM now: Deliver Us F..."}]);
When I fire up the Chrome Javascript Console I get an error

Read:1 Uncaught ReferenceError:stcCallback1001 is not defined
EDIT

I also tried the following for my store


rpc.stores.VimeoStore = new Ext.data.Store({
id: 'VimeoStore',
model: 'rpc.models.VimeoModel',
proxy: {
type: 'scripttag',
url: WebService.Url + WebService.Vimeo.Read,
method: 'GET',
callbackParam: 'idSession',
timeout: '15000',
reader: {
type: 'json'
}
},
autoLoad: true
});
and now my JSONP looks like this


1308021874668([{"id":25036464,"title":"Power of A Surrendered Li..."},{"id":25036610,"title":"Child Dedication June 2011"},{"id":24734142,"title":"Power of A Surrendered Li..."},{"id":24884833,"title":"Finance Update June 2011"},{"id":24587711,"title":"Papua, Indonesia Sharing ..."},{"id":24232427,"title":"ICHTHUS: Coming King"},{"id":23868560,"title":"ICHTHUS: Healer"},{"id":23486615,"title":"ICHTHUS: Sanctifier"},{"id":23211649,"title":"ICHTHUS: Saviour"},{"id":23867961,"title":"Elder Announcement re: Br..."},{"id":22998163,"title":"Triumph of Grace: Risen L..."},{"id":23687914,"title":"Triumph of Grace: Reignin..."},{"id":23692076,"title":"KINGDOM now: For Thine Is..."},{"id":23694183,"title":"KINGDOM now: Deliver Us F..."}]);1308021874668([{"id":25036464,"title":"Power of A Surrendered Li..."},{"id":25036610,"title":"Child Dedication June 2011"},{"id":24734142,"title":"Power of A Surrendered Li..."},{"id":24884833,"title":"Finance Update June 2011"},{"id":24587711,"title":"Papua, Indonesia Sharing ..."},{"id":24232427,"title":"ICHTHUS: Coming King"},{"id":23868560,"title":"ICHTHUS: Healer"},{"id":23486615,"title":"ICHTHUS: Sanctifier"},{"id":23211649,"title":"ICHTHUS: Saviour"},{"id":23867961,"title":"Elder Announcement re: Br..."},{"id":22998163,"title":"Triumph of Grace: Risen L..."},{"id":23687914,"title":"Triumph of Grace: Reignin..."},{"id":23692076,"title":"KINGDOM now: For Thine Is..."},{"id":23694183,"title":"KINGDOM now: Deliver Us F..."}]);
But unfortunately it comes with a new error
Uncaught TypeError: number is not a function

bclinton
14 Jun 2011, 3:59 AM
I'm guessing the second one isn't working because a number is not a valid JavaScript function name.

The first one is probably not working because you have a wrong callback name. The JSONP request will generate the callback name and you need to retrieve it and use it to wrap your response. Check out the JSONP API docs. They show example java, php and asp code for doing this.

Also, you might want to get in the habit of returning metadata, in particular a "success" parameter, with your JSON response as shown in the API docs for JsonReader. I guess it's not necessary, but it can be useful if you want to use the success and failure callbacks.

rockinthesixstring
14 Jun 2011, 5:26 AM
Thanks for your reply. I've been digging around and I'm just not having a lot of luck. I've built an ASP.NET MVC WebService that returns the data dynamically, and uses the
_dc //this seems to be generated by sencha touch querystring parameter in it's JSONP creation.

I'm fairly confident that I've got the WebService returning data appropriately, I'm just not sure how to go about wiring up Sencha. I took a peek at the docs (http://dev.sencha.com/deploy/touch/docs/?class=Ext.util.JSONP) like you said, but I'm still unclear. If you have time, I could sure use a little more direction.

bclinton
14 Jun 2011, 7:32 AM
Yeah, it can be confusing at first but that's not it. The "_dc" is something else. I believe it's meant to prevent caching.

The callback will be sent automatically with the variable name "callback" (as long as you don't change it with the "callbackParam" of the proxy.) It will be appended to the URL like this:


?callback=stcCallback1001

* where "callback" is the name of the variable being sent to your server
* and "stcCallback1001" is the value of the callback variable being sent to your server. This is what you use to wrap your response.

of course the "stcCallback1001" part can change, that's why you need to get it from the request being sent to your server.

I don't use .ASP very often, but the examples I pointed you to shows an .ASP script getting the callback name like this:


String cb = Request.Params.Get("callback");

and then wrapping it around the JSON response like this:


responseString = cb + "(" + jsonString + ")";

You may also want to look at the docs for ScriptTagProxy for further explanation: http://dev.sencha.com/deploy/touch/docs/?class=Ext.util.JSONP?class=Ext.data.ScriptTagProxy

rockinthesixstring
14 Jun 2011, 7:50 AM
So by removing the



callbackParam: 'idSession',


from my rpc.stores.VimeoStore, my JSONP Response looks like this.



stcCallback1001([{"id":25036464,"title":"Power of A Surrendered Li..."},{"id":25036610,"title":"Child Dedication June 2011"},{"id":24734142,"title":"Power of A Surrendered Li..."},{"id":24884833,"title":"Finance Update June 2011"},{"id":24587711,"title":"Papua, Indonesia Sharing ..."},{"id":24232427,"title":"ICHTHUS: Coming King"},{"id":23868560,"title":"ICHTHUS: Healer"},{"id":23486615,"title":"ICHTHUS: Sanctifier"},{"id":23211649,"title":"ICHTHUS: Saviour"},{"id":23867961,"title":"Elder Announcement re: Br..."},{"id":22998163,"title":"Triumph of Grace: Risen L..."},{"id":23687914,"title":"Triumph of Grace: Reignin..."},{"id":23692076,"title":"KINGDOM now: For Thine Is..."},{"id":23694183,"title":"KINGDOM now: Deliver Us F..."}]);stcCallback1001([{"id":25036464,"title":"Power of A Surrendered Li..."},{"id":25036610,"title":"Child Dedication June 2011"},{"id":24734142,"title":"Power of A Surrendered Li..."},{"id":24884833,"title":"Finance Update June 2011"},{"id":24587711,"title":"Papua, Indonesia Sharing ..."},{"id":24232427,"title":"ICHTHUS: Coming King"},{"id":23868560,"title":"ICHTHUS: Healer"},{"id":23486615,"title":"ICHTHUS: Sanctifier"},{"id":23211649,"title":"ICHTHUS: Saviour"},{"id":23867961,"title":"Elder Announcement re: Br..."},{"id":22998163,"title":"Triumph of Grace: Risen L..."},{"id":23687914,"title":"Triumph of Grace: Reignin..."},{"id":23692076,"title":"KINGDOM now: For Thine Is..."},{"id":23694183,"title":"KINGDOM now: Deliver Us F..."}]);

Unfortunately it throws this error



Uncaught ReferenceError: stcCallback1001 is not defined

bclinton
14 Jun 2011, 7:57 AM
I'm sorry, but I have to ask... Where are you getting the "stcCallback1001" that you are using to wrap your json? Are you getting it from the request or are you just popping it in there?

I ask because that looks like the error you get when the callback wrapper your server sends back to your proxy doesn't match the callback name that was specified by Sencha when the request was made.

Can you post the Request URL that is being sent to your server? It should be pretty easy to find if you are using a debugger like Chrome developer tools.

rockinthesixstring
14 Jun 2011, 8:02 AM
Yeah, the request from my Store looks like this


http://rpc.infinitas.ws/Vimeo/Read?_dc=1308067234445&limit=25&callback=stcCallback1001

Then in my WebService, I'm wrapping my JSON in the callback querystring parameter.



public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}

this.JsonCallback = context.HttpContext.Request["jsoncallback"];

if (string.IsNullOrEmpty(this.JsonCallback))
this.JsonCallback = context.HttpContext.Request["callback"];

if (string.IsNullOrEmpty(this.JsonCallback))
throw new ArgumentNullException("JsonCallback required for JSONP response.");

HttpResponseBase response = context.HttpContext.Response;

if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/javascript";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
response.Write(string.Format("{0}({1});", this.JsonCallback, serializer.Serialize(Data)));
}
}

rockinthesixstring
14 Jun 2011, 8:09 AM
Feel free to take a look at the staging site

http://rpcm.infinitas.ws/

rockinthesixstring
14 Jun 2011, 8:42 AM
I've modified the WebService to return "success" and "results".

I've also updated the Store



rpc.stores.VimeoStore = new Ext.data.Store({
id: 'VimeoStore',
model: 'rpc.models.VimeoModel',
proxy: {
type: 'scripttag',
url: WebService('Vimeo', 'Read'),
method: 'GET',
reader: {
type: 'json',
root: 'results'
}
},
autoLoad: true
});


Unfortunately I'm still getting the same results.

bclinton
14 Jun 2011, 9:17 AM
It looks there is a problem with your response. It looks like you are spitting out the same wrapped JSON string twice.

http://rpc.infinitas.ws/Vimeo/Read?_dc=1308069770341&limit=25&callback=stcCallback1001



stcCallback1001({"results":[{"id":25036464,"title":"Power of A Surrendered Li..."},{"id":25036610,"title":"Child Dedication June 2011"},{"id":24734142,"title":"Power of A Surrendered Li..."},{"id":24884833,"title":"Finance Update June 2011"},{"id":24587711,"title":"Papua, Indonesia Sharing ..."},{"id":24232427,"title":"ICHTHUS: Coming King"},{"id":23868560,"title":"ICHTHUS: Healer"},{"id":23486615,"title":"ICHTHUS: Sanctifier"},{"id":23211649,"title":"ICHTHUS: Saviour"},{"id":23867961,"title":"Elder Announcement re: Br..."},{"id":22998163,"title":"Triumph of Grace: Risen L..."},{"id":23687914,"title":"Triumph of Grace: Reignin..."},{"id":23692076,"title":"KINGDOM now: For Thine Is..."},{"id":23694183,"title":"KINGDOM now: Deliver Us F..."}],"success":true});stcCallback1001({"results":[{"id":25036464,"title":"Power of A Surrendered Li..."},{"id":25036610,"title":"Child Dedication June 2011"},{"id":24734142,"title":"Power of A Surrendered Li..."},{"id":24884833,"title":"Finance Update June 2011"},{"id":24587711,"title":"Papua, Indonesia Sharing ..."},{"id":24232427,"title":"ICHTHUS: Coming King"},{"id":23868560,"title":"ICHTHUS: Healer"},{"id":23486615,"title":"ICHTHUS: Sanctifier"},{"id":23211649,"title":"ICHTHUS: Saviour"},{"id":23867961,"title":"Elder Announcement re: Br..."},{"id":22998163,"title":"Triumph of Grace: Risen L..."},{"id":23687914,"title":"Triumph of Grace: Reignin..."},{"id":23692076,"title":"KINGDOM now: For Thine Is..."},{"id":23694183,"title":"KINGDOM now: Deliver Us F..."}],"success":true});


Let's hope that's it, because your code looks fine to me :)

rockinthesixstring
14 Jun 2011, 9:31 AM
yeah that's probably it... Now to figure out why it's being added by the service like that... cuz that's just weird.

rockinthesixstring
14 Jun 2011, 11:31 AM
Ok, I've fixed my WebService to NOT emit duplicate content, and now the error has gone away.

UNFORTUNATELY

There is no "video" content in my VideoPanel. All of the rest of the code is unchanged, My model matches the JSONP from the web service, I'm calling the Store from the VideoView, and there is nothing showing up in the card.

Again, the service is here
http://rpc.infinitas.ws/vimeo/read
and the mobile app is here
http://rpcm.infinitas.ws

Ahhhhh, I feel I'm so close and just missing something basic.


EDIT:
I think I'm going to punch this new bit over to a new thread!!!

Thanks for all the help.