JQuery_ Novice to Ninja - Earle Castledine [93]
This means we can use all the jQuery actions we already know to traverse the DOM and pick out what we’re interested in. For example, we can use find() to search for nodes by name, and next and prev to traverse siblings:
chapter_06/13_consuming_xml/script.js (excerpt)
success: function(data) {
$(data)
.find('celebs')
.children()
.each(function() {
var node = $(this);
var id = node.attr('id');
var name = node.find('name').text();
var image = node.find('image').text();
_gallery.display({'id': id, 'image': image, 'name': name});
});
}
We loop over each celeb node and extract its ID, name, and image URL, which we then combine into an object literal and pass to our display method. (This is why JSON is so handy: it already comes packaged up as a JavaScript object!)
We next have to amend the display function itself to accept our new data object rather than a simple text string. Our data object has some additional information that we’ll need to access when it comes time to load the tags, namely an ID, which we’ll pass to the tag service. We’ll store that value in the img tag itself, via the jQuery data function.
Now that we have access to a celebrity’s name in our data, we can also fix an accessibility and standards-compliance issue with our previous code: we can add an alt attribute to our images, containing the celebrity’s name:
chapter_06/13_consuming_xml/script.js (excerpt)
display: function(dataItem) {
$('')
.attr({
src: '../../images/' + dataItem.image,
alt: dataItem.name
})
.hide()
.data('id', dataItem.id)
.load(function() {
$(this).fadeIn();
})
.click(function() {
CELEB.load($(this).data('id'));
})
.appendTo('#gallery');
}
Being able to augment DOM nodes with data is tremendously useful; we can now know easily which ID we need to load tag data for inside the click handler. Once we have the ID we’re ready to move on to the next stage of the image tagging feature: grabbing and displaying the tag data itself.
We could lump this logic in to the GALLERY widget, but now we’re dealing with a whole new context. Instead, we’ll separate it out into a new CELEB widget to keep it nice and readable:
chapter_06/13_consuming_xml/script.js (excerpt)
var CELEB = {
url: 'celebs.json',
load: function(image_id) {
var _celeb = this;
$('#details input').attr('disabled', 'disabled');
$.getJSON(
this.url,
function(data) {
$('#details input').removeAttr('disabled');
_celeb.display(data);
});
},
display: function(data) {
$('#id').val(data.id);
$('#name').val(data.name);
$('#tags').val(data.tags.join(" "));
}
}
Thankfully our developer is now sold on the JSON idea, and has set up a JSON data service to allow us to grab the tag information. This consists of an ID, a name, and an array of tags for us to display.
We use $.getJSON to fetch the data—but this lacks a beforeSend or complete event handler we can react to in order to give the user some visible feedback that a request is occurring. What we’ll do instead is disable the form fields before we send the request, and re-enable them when the data comes back, using the attr method to set the disabled attribute.
Once the data comes back, we pass it to the display function and populate the fields. Yet another successful Ajax implementation! Of course, with our simulated JSON response, the celebrity name and tags will be the same no matter which image you click. But you can try changing the contents of celebs.json to simulate different server responses.
Sending Form Data
All this displaying of data is great—but if we want to reap some of the benefits of user-generated content and build up a loyal celebrity-obsessed community, we’ll have to start moving some data in the other direction!
Naturally jQuery can help us out with this—we just need to collate our data into a form that can be sent. We could read all of the field values and concatenate them into a string—which would be quite cumbersome, really—or create an object that holds all the key/value pairs from the form. The latter would