Skip to content

Backbone Model Validation — Ensuring Data Integrity

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Backbone Model Validation. We cover key concepts, practical examples, and best practices to help you master this topic.

Backbone Model validation lets you define rules that check attribute values before saving. The validate method runs automatically during set() (if {validate: true} is passed) and always during save(). Invalid data triggers an invalid event and blocks persistence.

What You'll Learn

You'll learn how to define validation rules, trigger validation on set and save, handle validation errors, use custom error messages, and create reusable validation patterns.

Why It Matters

Validating data on the client prevents bad data from reaching the server, reduces network requests, and gives users immediate feedback. Security tools should validate input before analysis to avoid processing malformed data.

Real-World Use

A malware analysis platform validates file hash format before submitting to the scanning engine. If the hash is not a valid SHA256 string (64 hex characters), the Model refuses to save and shows an error instantly.

flowchart LR
    A[User input] --> B[set or save]
    B --> C[validate method]
    C --> D{Valid?}
    D -->|Yes| E[Update attributes]
    D -->|No| F[invalid event]
    F --> G[error callback]
    G --> H[Show error message]
    E --> I[save to server]

Basic Validation

Define a validate method that returns an error string if validation fails. If it returns nothing, validation passes.

var Task = Backbone.Model.extend({
  defaults: {
    title: '',
    priority: 'medium'
  },

  validate: function(attrs) {
    if (!attrs.title || attrs.title.trim() === '') {
      return 'Title cannot be empty';
    }
    if (attrs.title.length > 200) {
      return 'Title must be under 200 characters';
    }
  }
});

var task = new Task();
task.on('invalid', function(model, error) {
  console.log('Validation error:', error);
});

// Trigger validation manually
task.set({ title: '' }, { validate: true });
console.log('After invalid set:', task.get('title'));

Expected output:

Validation error: Title cannot be empty
After invalid set: (default empty string)

Validation on Save

save() always runs validation before sending data to the server. If validation fails, the error callback fires.

var User = Backbone.Model.extend({
  urlRoot: '/api/users',

  validate: function(attrs) {
    if (!attrs.email) {
      return 'Email is required';
    }
    if (attrs.email.indexOf('@') === -1) {
      return 'Email must contain @';
    }
    if (!attrs.password || attrs.password.length < 6) {
      return 'Password must be at least 6 characters';
    }
  }
});

var user = new User({ email: 'invalid', password: '123' });
user.save(null, {
  error: function(model, response) {
    // response is the validation error string
    console.log('Save failed:', response);
  }
});

Expected output:

Save failed: Email must contain @

Multiple Field Validation

Validate combinations of fields together. A common pattern is checking that two fields match.

var Registration = Backbone.Model.extend({
  defaults: {
    username: '',
    password: '',
    confirmPassword: ''
  },

  validate: function(attrs) {
    var errors = [];

    if (!attrs.username || attrs.username.length < 3) {
      errors.push('Username must be at least 3 characters');
    }
    if (!attrs.password || attrs.password.length < 8) {
      errors.push('Password must be at least 8 characters');
    }
    if (attrs.password !== attrs.confirmPassword) {
      errors.push('Passwords do not match');
    }

    if (errors.length > 0) {
      return errors.join(', ');
    }
  }
});

var reg = new Registration({
  username: 'ab',
  password: '12345',
  confirmPassword: 'different'
});

reg.on('invalid', function(model, error) {
  console.log('Errors:', error);
});

reg.save(null, { error: function(m, e) { console.log('Blocked:', e); } });

Expected output:

Errors: Username must be at least 3 characters, Password must be at least 8 characters, Passwords do not match
Blocked: Username must be at least 3 characters, Password must be at least 8 characters, Passwords do not match

Async Validation with Server Check

Backbone's built-in validation is synchronous. For async validation (e.g., checking if a username is taken), run validation before calling save manually.

var SignupForm = Backbone.Model.extend({
  defaults: {
    username: '',
    email: ''
  },

  validate: function(attrs) {
    if (!attrs.username) return 'Username required';
    if (!attrs.email) return 'Email required';
  }
});

var form = new SignupForm({ username: 'newuser', email: 'test@test.com' });

// Simulate async server check
function checkUsername(username) {
  return $.Deferred().resolve({ available: true });
}

form.on('invalid', function(m, e) { console.log('Error:', e); });

checkUsername(form.get('username')).done(function(result) {
  if (!result.available) {
    console.log('Username taken — show error');
  } else {
    form.save(null, {
      success: function() { console.log('Registered!'); },
      error: function(m, e) { console.log('Save error:', e); }
    });
  }
});

Expected output:

Username taken — show error

Conditional Validation

Apply rules based on other attribute values. Different states may require different validation.

var Order = Backbone.Model.extend({
  defaults: {
    type: 'standard',
    shippingAddress: '',
    expressFee: 0
  },

  validate: function(attrs) {
    if (!attrs.shippingAddress) {
      return 'Shipping address is required';
    }

    // Express orders require a phone number
    if (attrs.type === 'express' && !attrs.phone) {
      return 'Phone number required for express shipping';
    }

    if (attrs.type === 'international' && !attrs.customsInfo) {
      return 'Customs info required for international orders';
    }
  }
});

var order = new Order({ type: 'express', shippingAddress: '123 Main St' });
order.on('invalid', function(m, e) { console.log(e); });

order.save(null, { error: function(m, e) { console.log(e); } });

order.set({ phone: '555-0100' }, { validate: true });
console.log('Order valid now:', order.isValid());

Expected output:

Phone number required for express shipping
Order valid now: true

Using isValid

The isValid() method runs validation without triggering events or blocking save. Use it to check state before showing forms.

var Task = Backbone.Model.extend({
  defaults: { title: '', priority: '' },
  validate: function(attrs) {
    if (!attrs.title) return 'Title required';
    if (!attrs.priority) return 'Priority required';
  }
});

var task = new Task({ title: 'Test' });
console.log('Valid without priority:', task.isValid());

task.set('priority', 'high');
console.log('Valid with priority:', task.isValid());

Expected output:

Valid without priority: false
Valid with priority: true

Common Mistakes

  1. Not passing {validate: true} to set(). By default, set() does NOT run validation. Only save() always validates. Use set({...}, {validate: true}) to validate on set.
  2. Returning a string instead of nothing on success. If validate returns any truthy value, Backbone treats it as an error. Return undefined or nothing when valid.
  3. Using alert() in validation. Validation errors should be returned as strings, not shown with alert(). Let the View handle display.
  4. Not listening to the invalid event. If no one listens for invalid, validation errors are silently swallowed. Always attach an invalid handler.
  5. Relying only on client-side validation. Server-side validation is mandatory. Client-side validation is for UX, not security.

Practice Questions

  1. How do you trigger validation when calling set()?
  2. What does the validate method need to return to indicate success?
  3. How do you check if a Model is currently valid without triggering events?
  4. What happens if save() is called and validation fails?
  5. Challenge: Create a PasswordReset Model with validation rules: password must be 8+ chars, contain a number and special character, and match confirmPassword. Test all three error cases.

FAQ

Does `validate` run on every `set()` call?

No, only when {validate: true} is passed to set(). It always runs during save().

Can I return multiple error messages?

Yes. Return a string with delimiters like errors.join(', ') or return an array and parse it in the error handler.

What event fires when validation fails?

The invalid event fires on the Model. If no invalid listener exists, the error callback on save() catches it.

Can validation be async?

Backbone's built-in validate is synchronous. For async checks (server validation), perform the check before calling save().

Does validation prevent `set()` from updating attributes?

Yes. When {validate: true} is passed and validation fails, the attributes are NOT updated.

Mini Project

Create a ServerConfig Model that validates: hostname is required and matches a regex, port is between 1 and 65535, protocol is http or https, and timeout is a positive number. Test all validation rules. Attach an invalid handler that logs each error.

What's Next

Now that you can validate Models, learn Backbone Collections for managing groups of Models. Then explore Backbone Collection Methods for filtering, sorting, and querying data.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro