JQuery_ Novice to Ninja - Earle Castledine [101]
chapter_07/09_inline_editing/script.js (excerpt)
// Determine what kind of form element we need
var editElement = $editable.hasClass('editable') ?
'' : '';
// Replace the target with the form element
$(editElement)
.val(contents)
.appendTo($editable)
.focus()
.blur(function(e) {
$editable.trigger('blur');
});
You might be curious about the use of the trigger function. It’s simply a different way to cause an event to fire (so, in this example, we could also have used the $editable.blur() syntax we’ve already seen). The trigger action is more flexible than its shorter counterpart—but for now we’ll just stick with the basic usage.
trigger is being used in this example for clarity: to show whoever is reading the code that we want to manually fire an event. In this case we’re just passing on the event; the input was blurred, so we tell the original element that it’s time to finish editing. We could manage all of this inside the input box’s blur event handler, but by delegating the event like this, we avoid nesting our code another level (which would make it harder to read). It also makes sense to let the original element deal with its own logic.
The counterpart to trigger is bind. bind lets us add event handlers to an object. Sound familiar? So far we’ve been binding events by using shorthand convenience methods like click, hover, ready, and so on. But if you pop the hood, you’ll see that internally they all rely on bind.
The bind action takes a string containing the name of the event to bind, and a callback function to run. You can also bind multiple events to an item in a single call by wrapping them in an object. For example, our code attached three separate events to .editable and .editable-area elements: click, hover, and blur. If you wanted to, you could rewrite that with the bind syntax:
$('.editable, .editable-area').bind({
hover: function(e) {
// Hover event handler
},
click: function(e) {
// Click event handler
},
blur: function(e) {
// Blur event handler
}
});
Let’s return to our example; with the editing over, we can go back to our default state. We’ll grab the value from the form element, and send it to the server with $.post, putting a “Saving …” message in place as we do so. When the POST is done, we eliminate the message and replace it with the updated value. As with the Ajax functionality we saw in the previous chapter, we’re faking a server-side response with an empty save file. In a real world application, you’d want to check that the changes had actually been saved to the database by checking the response data:
chapter_07/09_inline_editing/script.js (excerpt)
.blur(function(e) {
// end the inline editing
var $editable = $(this);
var contents = $editable.find(':first-child:input').val();
$editable
.contents()
.replaceWith('Saving … ');
// post the new value to the server along with its ID
$.post('save',
{id: $editable.attr('id'), value: contents},
function(data) {
$editable
.removeClass('active-inline')
.contents()
.replaceWith(contents);
});
});
There are two new jQuery functions in this block of code, but both of them are fairly self-explanatory. contents() returns the entire contents of a DOM node, which can include other DOM elements and/or raw text, and replaceWith() swaps whatever you’ve selected with whatever you pass to it. Be careful when using the latter method; in our example we know that contents() will only return one element—but if it returned multiple elements, each of those elements would be replaced with the same loading message!
Autocomplete
We’ve appeased the client—he’s having a blast playing with the inline edit fields over in the corner. While we have a few minutes up our sleeves until his next