Backbone.js Model validation fails to prevent Model from saving
- by Benjen
I have defined a validate method for a Backbone.js Model. The problem is that even if validation fails (i.e. the Model.validate method returns a value) the post/put request is still sent to the server. This contradicts what is explained in the Backbone.js documentation. I cannot understand what I am doing wrong.
The following is the Model definition:
/**
* Model - Contact
*/
var Contact = Backbone.Model.extend({
urlRoot: '/contacts.json',
idAttribute: '_id',
defaults: function() {
return {
surname: '',
given_name: '',
org: '',
phone: new Array(),
email: new Array(),
address: new Array({
street: '',
district: '',
city: '',
country: '',
postcode: ''
})
};
}
validate: function(attributes) {
if (typeof attributes.validationDisabled === 'undefined') {
var errors = new Array();
// Validate surname.
if (_.isEmpty(attributes.surname) === true) {
errors.push({
type: 'form',
attribute: 'surname',
message: 'Please enter a surname.'
});
}
// Validate emails.
if (_.isEmpty(attributes.email) === false) {
var emailRegex = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,6}$/i;
// Stores indexes of email values which fail validation.
var emailIndex = new Array();
_.each(attributes.email, function(email, index) {
if (emailRegex.test(email.value) === false) {
emailIndex.push(index);
}
});
// Create error message.
if (emailIndex.length > 0) {
errors.push({
type: 'form',
attribute: 'email',
index: emailIndex,
message: 'Please enter valid email address.'
});
}
}
if (errors.length > 0) {
console.log('Form validation failed.');
return errors;
}
}
}
});
Here is the View which calls the Model.save() method (see: method saveContact() below). Note that other methods belonging to this View have not been included below for reasons of brevity.
/**
* View - Edit contact form
*/
var EditContactFormView = Backbone.View.extend({
initialize: function() {
_.bindAll(this, 'createDialog', 'formError', 'render', 'saveContact', 'updateContact');
// Add templates.
this._editFormTemplate = _.template($('#edit-contact-form-tpl').html());
this._emailFieldTemplate = _.template($('#email-field-tpl').html());
this._phoneFieldTemplate = _.template($('#phone-field-tpl').html());
// Get URI of current page.
this.currentPageUri = this.options.currentPageUri;
// Create array to hold references to all subviews.
this.subViews = new Array();
// Set options for new or existing contact.
this.model = this.options.model;
// Bind with Model validation error event.
this.model.on('error', this.formError);
this.render();
}
/**
* Deals with form validation errors
*/
formError: function(model, error) {
console.log(error);
},
saveContact: function(event) {
var self = this;
// Prevent submit event trigger from firing.
event.preventDefault();
// Trigger form submit event.
eventAggregator.trigger('submit:contactEditForm');
// Update model with form values.
this.updateContact();
// Enable validation for Model. Done by unsetting validationDisabled
// attribute. This setting was formerly applied to prevent validation
// on Model.fetch() events. See this.model.validate().
this.model.unset('validationDisabled');
// Save contact to database.
this.model.save(this.model.attributes, {
success: function(model, response) {
if (typeof response.flash !== 'undefined') {
Messenger.trigger('new:messages', response.flash);
}
},
error: function(model, response) {
console.log(response);
throw error = new Error('Error occured while trying to save contact.');
}
}, { wait: true });
},
/**
* Extract form values and update Contact.
*/
updateContact: function() {
this.model.set('surname', this.$('#surname-field').val());
this.model.set('given_name', this.$('#given-name-field').val());
this.model.set('org', this.$('#org-field').val());
// Extract address form values.
var address = new Array({
street: this.$('input[name="street"]').val(),
district: this.$('input[name="district"]').val(),
city: this.$('input[name="city"]').val(),
country: this.$('input[name="country"]').val(),
postcode: this.$('input[name="postcode"]').val()
});
this.model.set('address', address);
}
});