Using JSONP With $resource In AngularJS
Ultimately, the problem was really one of documentation. JSONP (or JSON with Padding) is mentioned in the $resource API; but, it's really only documented well in the $http API, which I have yet to dig into.
When I converted the $resource from a GET request to a JSONP request, I started off by simply switching the method to "JSONP". Coming from a jQuery background, I assumed that the "callback" parameter would get automatically generated and applied to the outgoing request. But, it did not.
Then, I tried adding an explicit "callback" parameter to the JSONP request configuration. But, this still didn't work. The network activity looked right; but, AngularJS was rejecting the request with an error.
Finally, I jumped over to the $http documentation and figured out where I was going wrong. Not only do I have to explicitly define my "callback" parameter in AngularJS, the callback parameter has to have the set value, "JSON_CALLBACK". Once I added this to the outgoing request configuration, the JSONP request started working.
It's an interesting approach. AngularJS looks at the outgoing URL and replaces the phrase "JSON_CALLBACK" with an auto-generated callback name. If you make the same JSONP request a few times in a row, you'll notice that the callback name increments in the URL:
As you can see, AngularJS generates functions that are accessible off the global angular namespace.
To pull this post together, I put together a simple little demo that makes a JSONP request for a list of friends and then renders the list on the page:
As you can see, the $resource instance is defined with the default parameter, callback: "JSON_CALLBACK". I'm then binding to the underlying $promise object of the response which will be resolved when the JSONP callback is invoked.
NOTE: jQuery seems to be able to access the proper status code in Firefox. As such, I assume the issue is one of cross-browser normalization? Or maybe a bug in AngularJS? I'm not sure.
Ultimately, I probably shouldn't use the $resource service with a JSONP request. $resource provided a level of abstraction that doesn't really add much value with the limited functionality of a JSONP request. I used it primarily because it was already in place; and, because I'm not super familiar with the underlying $http service... yet.
Want to use code from this post? Check out the license.
Any idea how to remove the auto-generate feature of JSON_CALLBACK. I would like to cache the service urls on the server. It is not working as angular auto creates the angular callbacks dynamically for each call.
Appreciate your help!
I am not sure what auto-generate feature you are talking about? Do you mean that you want to cache the JSONP response locally? If so, it looks like you should be able to provide the "cache" configuration when defining the $resource. That said, I haven't tried it myself.
Thanks for getting back.
From your blog, "It's an interesting approach. AngularJS looks at the outgoing URL and replaces the phrase "JSON_CALLBACK" with an auto-generated callback name. If you make the same JSONP request a few times in a row, you'll notice that the callback name increments in the URL:
As you mentioned, the JSON_CALLBACK is been auto generated by angular. But in my case, I would like the Service URL to be cached in the server side.
let say, http://api.x.com/service?id=123 would be cached if I turn the cache ON. But as the angular adds up the dynamic callbacks, the cache feature is not working in the server as the Url may vary on each request
So, I would like to know any alternative that would help me to enable the cache on server. I came across an approach where they suggest to use a custom function that resembles the callback method name.
But I am not sure how efficient this is and how it handles parallel request.
Appreciate your help!
Thanks Ben, really helpful article.
Just to confirm though, this will only work with GET methods, correct? there is no way to use jsonp for POST methods? Is there a work around to make POST Cross-Domain request?
Really a nice article. I have a same question as Vijay. Is there a way we can have static callback instead of dynamic callbacks