Last night I was able to build up a Rails-like errors class for encapsulating Backbone.js errors. In the end, I was still pulling out the full error messages to report back like this:
Tonight, I hope to be able to highlight the offending fields.
The
Errors
class so far boast the following interface: var Errors = function(options) {...};
_.extend(Errors.prototype, {
isEmpty: function() {...},
add: function(attribute, error) {...},
each: function(callback) {...},
full_messages: function() {...}
});
So I ought to be able to use the each
method to iteration over each field with an error (along with the error message). The HTML in the edit dialog looks like:<div id="edit-dialog" title="Edit calendar appointment">
<h2 class="startDate"></h2>
<div style="display: none" class="errors"></div>
<p>
<label>title<br/>
<input type="text" name="title"/>
</label>
</p>
<p>
<label>description<br/>
<input type="text" name="description"/>
</label>
</p>
</div>
(the values of date, title, and description are populated by my Backbone view)In the edit-appointment Backbone view (a singleton view because it re-uses a single jQuery UI dialog), the OK button's click event is bound to the
update()
method: var AppointmentEdit = new (Backbone.View.extend({
// ....
events : {
'click .ok': 'update'
},
update: function() {
var attributes = { /* pull from the dialog input fields */};
var options = { /* ... */ };
this.model.save(attributes, options);
}
}));
The update()
method tells the model to save itself. Success or failure of that save is handled by callbacks inside the options
object literal passed to save: var AppointmentEdit = new (Backbone.View.extend({
// ...
update: function() {
var attributes = { /* pull from the dialog input fields */ };
var options = {
// close the dialog if save was successful
success: function() { $('#edit-dialog').dialog("close"); },
// draw error messages in the dialog if there was a validation failure
error: function(model, errors) {
// display full messages at the top of the dialog
var full_messages = errors.full_messages();
$('.errors', '#edit-dialog').
html(full_messages.join("<br/>")).
show();
});
}
};
this.model.save(attributes, options);
}
}));
So far, I am only adding the full error messages. To highlight the individual fields with errors, I iterate over each error from my Errors
object. For each, I find the <label>
tag that has an input with a name that is same as the field with the error message. If the title
field has an error, then I find the <label>
containing the title
input field. For each such label, I add the "error"
class to it (which makes the background bright yellow). Lastly, I wrap each input field inside that <label>
with an "error"
class <div>
: var AppointmentEdit = new (Backbone.View.extend({
// ...
update: function() {
var attributes = { /* ... */ };
var options = {
//....
error: function(model, errors) {
// ...
errors.each(function(attribute, message) {
$('label', '#edit-dialog').
has('input[name=' + attribute + ']').
addClass('error').
find('input').
wrap('<div class="error"/>');
});
}
};
this.model.save(attributes, options);
}
}));
And that works:Yay!
The only deficiency with this approach is when I fix one field, only to introduce an error in another:
I can address that with:
var AppointmentEdit = new (Backbone.View.extend({
// ...
update: function() {
$('.error').removeClass('error');
//...
}
});
I think that about does it for my validations exploration. Unless I can think of something else to explore here, I will likely move on to a different Backbone topic tomorrow.Day #155
No comments:
Post a Comment