JSON for jQuery
Update 2007-09-13: As of version 1.2, the jQuery core now supports cross-domain JSONP downloads as part of the native Ajax support. I suggest you use this support instead of the plugin.
jQuery is a nifty new JavaScript library by John Resig. It features a $()
function like the one in Prototype.js, but beefed up with CSS and XPath selectors, and with the ability to chain methods to do interesting things with concise code.
Unlike Prototype, jQuery doesn’t mess around with built-in JavaScript objects. It’s new—too new to have a version number!—but I’ve been writing some code with it and enjoying it.
jQuery provides an easy way to write plugin methods to extend the $
function. For you JSON fans out there, here is a JSON plugin for jQuery which lets you write code like this:
You can of course use an anonymous function if you prefer:
Or, using jQuery’s method chaining, you can combine calls like this code which displays a “Loading…” message when it starts loading the JSON resource:
To install the plugin, simply paste this code into a .js file and load it after loading jquery.js:
This adds a json()
method to the $
function. The first argument is the URL to the JSON resource, with the text {callback}
wherever the JSON callback method should be provided. In a JSONP URL, you would use jsonp={callback}
; in a Yahoo! JSON URL you would use format=json&callback={callback}
.
The second argument is the callback function itself. When the JSON resource finishes loading, this function will be called with a single argument, the JSON object itself. Inside the callback function, this
is a reference to the HTML element found by the $
function. (If $
found more than one element, the callback function is called for each of them.)
The callback function is required, so this code won’t work with plain JSON APIs like del.icio.us that don’t let you specify a callback function. This would be easy enough to fix; I didn’t need it for the code I was writing, and didn’t think of it until just now. :-)
The code goes to a bit of extra work to create both an array entry and a unique global name for each callback. The global name is what is substituted into the {callback} part of the URL. It uses this name instead of the array reference to ensure compatibility with any JSON APIs that don’t allow special characters in the callback name. In fact, in the current code the callbacks[]
array entries are not really used, but I figured it could be handy to have an array of all outstanding callbacks.
Update: John Resig suggested a couple of improvements to the code, so it’s updated, simpler and better now.
Update 2: Code updated to include Stephen and Brent’s fixes from the comments.
I’m amazed at how neat jquery makes things simpler. I thought prototype was cool, but I’m beginning to like what you and John are doing with jquery even more…. you have one more convert here!
BTW, got to learn how you do code syntax coloring!!
Thanks, Ashutosh. The code syntax coloring uses GeSHi, the Generic Syntax Highlighter. I modified an existing Drupal plugin to make better use of this code formatter, and I’ve been meaning to post it on the Drupal site or here. Sorry about that, I must take care of it.
I would also recommend lightweight syntex highlighter called “prettyprint” used on Google Code. It is lightweight and looks very clean.
Regarding this post. I came across it while searching for RSS to JSON converter plugin for jQuery. I thought I would share it here with everybody. The great thing about it is that you don’t need to setup any server-side scripts. All you need is a jQuery.js file. Everything is done on client side leveraging Google Feeds API.
Here is an example from original post:
<script src="jquery.jgfeed.js"></script>
<script>
$.jGFeed('https://twitter.com/statuses/user_timeline/26767000.rss',
function(feeds){
// Check for errors
if(!feeds){
// there was an error
return false;
}
// do whatever you want with feeds here
for(var i=0; i<feeds.entries.length; i++){
var entry = feeds.entries[i];
// Entry title
entry.title;
}
}, 10);
</script>
I can’t get this pointing to other thing than window object, inside the callback.
PS: other, less relevant thing, is that it would be nice not to depend on the callback functionality of the server.. (if it’s possible sometime).
An easy way to gain access to a
this
object inside a callback or nested function is through a closure. There is an example in the code above. The outermost$.fn.json
function begins with:Later, the JSON callback nested two levels deep uses that
_$_
variable when it needs a reference to the originalthis
object:I don’t recommend using the cryptic name
_$_
that I used in that code. These days I usually call itself
, so the code would be:and:
Looks great, just a warning that cb’s assignment is missing a terminating semicolon:
Even uncompressed these sometimes throw a syntax error in Opera.
hi, very cool! just curious about this… if you use
and your
(new Date()).getTime()
returns a 10+ digit number, wont your$.json.callbacks
array be huge? why not{ callbacks : {} }
?Thanks, Brent and Stephen. I updated the code to include your fixes.
Hi there,
We’re in the process of building JSON interfaces to our services. We’ve found a serious problem using this particular technique of dynamically adding script tags to the document head: IE leaks memory like a sieve when you do this. According to some MSDN documentation I read, they refuse to garbage collect script text on a page until the page is destroyed.
Given that we routinely send hundreds of kilobytes of JSON data across the channel, this became a problem for us very quickly. The solution is to wrap the script call inside a dynamically-generated iframe element.
To see a demo of our web-based traffic application, see https://mycommute.maptuit.com/?config=TrafficT.NYC.
There is a solution to Ie memory leak, you have to remove the obj(garbage collector) before you can removechild node.
Hi, I’m new with Json and I’ve tried to get this plugin to work since several days. Is there anybody who could give me an example. Thanks in advance! Mark
Has this functionality been included in the
Both functions let you download JSON data, but they use different techniques and are made for different situations.
$.json()
(this plugin) uses a dynamic script tag to download the JSON data. This lets it work across domains, but it requires that the JSON data be wrapped in a callback function (JSONP format).$.getJSON()
is an AJAX call, that is, it uses XMLHttpRequest. So it works only within the same domain—you can’t use it for cross-domain requests. But it doesn’t require JSONP format; it will work with any standard JSON data.Thanks Michael.
I looked at the jQuery sources in the mean time. To me, jQuerys $.ajax seems to be lacking a fallback mechanism in case ActiveX controls are disabled. This is where your solution — or Ralf Engelschalls — could help.
I added your code to my js files and put in the right order. I am new at this so I am trying to learn. When I runt he following code. I get an javascript error on my page and no output. Can you help me with what I am doing wrong. I am really trying to understand this stuff. Thanks.
Eric, do you have a test page you could post a link to? Or else let me know what the JavaScript error was?
I’ll try a test with your code, but if you have a link or error message that would give me a head start.
Eric, you were pretty close there. Here’s an updated version of your code that works:
I added a
log()
function to replace the alerts. If you load the page in Firefox with Firebug enabled, it will useconsole.debug()
to log the messages, including making objects like thejson
response clickable and browsable. If Firebug is not available, it falls back to analert()
call. The fancy.apply()
stuff is to make multiple arguments work in both these cases.There were two things wrong in the code. First, you need to call the
json
function with$(selector).json()
, whereselector
is an optional jQuery selector. You don’t need any selector in this particular case, so I left it empty. (In hindsight, my requirement for$()
with or without the selector was a bit goofy—I will probably update the code sometime to make it work the way you tried to use it.)After I fixed that, though, it still didn’t get to the callback function with the “json received” message. So I tried opening your Flickr feed URL directly in a browser, and found that the JSON response calls a function named
jsonFlickrFeed()
. I changed the{callback}
to MikeTest, so the URL ended withformat=json&jsonp=MikeTest
. I also tried changing it toformat=json&jsoncallback=MikeTest
as described on Flickr’s JSON API page, but the response still calledjsonFlickrFeed()
instead ofMikeTest()
.It appears that Flickr’s feed API doesn’t support the user-defined callback function name that this plugin normally requres. (Their REST API does support
jsoncallback=functionName
and works fine with the plugin.)A quick workaround for that is to simply define the
jsonFlickrFeed()
function directly instead of specifying the callback function in the$().json()
call. At this point the plugin isn’t doing much for you except for creating the dynamic script tag, but it does get things working.When I get a chance I’ll update the plugin to support this more directly. And hopefully Flickr will update their feed API to support the user-defined callback names as their REST API does.
Wow, all I have to say is THANK YOU. I really appreciate the time you took to help me understand this. I will be working on this today after I pick through your code you gave me. Thank you for teaching me the log().
BTW, because of Flickr’s hardcoded callback function name, the only part of the plugin that you’re really using is the
load()
function:So you could omit the plugin entirely and use this code instead:
Be sure to load your page with Firebug and watch the console log - it’s pretty cool to see your name show up in the JSON response.
Also, install the Firefox Web Developer toolbar if you don’t already have it. Load your page and then select Information/View JavaScript from the toolbar. A new window or tab will open showing all of the scripts loaded in the page—inline, .js files, and JSON downloads. Click the Collapse All link at the top of the page to see just the URLs. Very handy to check out your JSON downloads this way.
ABOUT JQUERY WITH JSON
please give me suggation
WITH COMPLETE EXAMPLE
Hi,
Is there a way to use the jquery $.ajax along with your plug-in and get a JSONP object?
Below is the code I have, but it’s getting a “XMLHttpRequest” error because I’m trying to call a resource from a sub-domain.
Matthew, it sounds like you are running into cross-domain security. If your page is loaded from a domain other than “sub.domain.tld” then
$.ajax
will fail.That is the whole point of the JSONP format with dynamic script tags as used in this plugin—it avoids all of the cross-domain security issues. You can load a script tag from any domain, and JSONP format is simply a way to request that a specific callback function name be executed with the JSON data as an argument.
Does your server actually provide JSONP output, where you can specify the callback function name in the URL? If it does, then you can use the plugin directly and not use
$.ajax
at all.Tell me a bit more and we can come up with a solution…
Hi Michael,
Excellent plugin first off. I love your closure solution for queuing the callbacks. I’ve actually used the idea of it for a recent plugin to use the Del.icio.us json feeds. I had to modify it to use an auto-incrementing array to house the callback references instead of the date-string based hash object due to the need to call several scripts in rapid succession. I was seeing callbacks overwritten due to them getting the exact same date string (I was surprised).
In any case… The main reason for my comment is to point out a problem I just fixed in my plugin and which your code appears to share. jQuery 1.1.4 now detects script elements being appended to the DOM using the
$().append()
method. When it detects one that also has a src attribute, it attempts to use $.ajax to grab the script and execute it. Our code will, for obvious reasons, cause that ajax call to fail. I had to go back to using real DOM methods to get it done. So, your 3rd to last line should be changed…Thanks again for the great plugin.
Thanks for the kind words and the heads-up, Paul.
As you probably know, the jQuery 1.2 core now supports cross-domain JSONP downloads natively. So there’s probably not much need for the plugin any more. I haven’t tested the new code yet, but it probably does a fine job.
Hello
I need your help on this.
Example: I have JSON data
Country Code
Belgium 106 China 103
How do I populate a HTML select dropdown box with the json data
Select Dropdown(Belgium, China)
Now when I select a value like China, it should traverse JSON and display the code.
Can someone show me an example of how, this can be done using JSON and Jquery.
Thanks
… the core implementation have some serious limitations.
I made jquery-jsonp to deal with them.