From b4d573c9436d2ec8d491269cc98bc04dd812ef70 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Mon, 1 Nov 2010 11:43:05 -0400 Subject: [PATCH] Merging in Chris Lloyd's Model#clear. Making validations run, if defined, on Model#clear and Model#unset --- backbone.js | 58 +++++++++++++++++++++++++++++++++------------------ test/model.js | 33 +++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 20 deletions(-) diff --git a/backbone.js b/backbone.js index 50dae76e..e393b7d2 100644 --- a/backbone.js +++ b/backbone.js @@ -142,19 +142,8 @@ if (attrs.attributes) attrs = attrs.attributes; var now = this.attributes; - // Run validation if `validate` is defined. If a specific `error` callback - // has been passed, call that instead of firing the general `"error"` event. - if (this.validate) { - var error = this.validate(attrs); - if (error) { - if (options.error) { - options.error(this, error); - } else { - this.trigger('error', this, error); - } - return false; - } - } + // Run validation. + if (this.validate && !this._performValidation(attrs, options)) return false; // Check for changes of `id`. if ('id' in attrs) this.id = attrs.id; @@ -176,25 +165,38 @@ return this; }, - // Remove an attribute from the model, firing `"change"` unless you choose to - // silence it. + // Remove an attribute from the model, firing `"change"` unless you choose + // to silence it. unset : function(attr, options) { options || (options = {}); var value = this.attributes[attr]; + + // Run validation. + var validObj = {}; + validObj[attr] = void 0; + if (this.validate && !this._performValidation(validObj, options)) return false; + + // Remove the attribute. delete this.attributes[attr]; if (!options.silent) { this._changed = true; this.trigger('change:' + attr, this); this.change(); } - return value; + return this; }, - - // Clears all attributes from the model, firing `"change"` unless you - // choose to silence it. + + // Clear all attributes on the model, firing `"change"` unless you choose + // to silence it. clear : function(options) { options || (options = {}); var old = this.attributes; + + // Run validation. + var validObj = {}; + for (attr in old) validObj[attr] = void 0; + if (this.validate && !this._performValidation(validObj, options)) return false; + this.attributes = {}; if (!options.silent) { this._changed = true; @@ -203,7 +205,7 @@ } this.change(); } - return old; + return this; }, // Fetch the model from the server. If the server's representation of the @@ -322,6 +324,22 @@ // `"change"` event. previousAttributes : function() { return _.clone(this._previousAttributes); + }, + + // Run validation against a set of incoming attributes, returning `true` + // if all is well. If a specific `error` callback has been passed, + // call that instead of firing the general `"error"` event. + _performValidation : function(attrs, options) { + var error = this.validate(attrs); + if (error) { + if (options.error) { + options.error(this, error); + } else { + this.trigger('error', this, error); + } + return false; + } + return true; } }); diff --git a/test/model.js b/test/model.js index 9160f079..04cfa900 100644 --- a/test/model.js +++ b/test/model.js @@ -102,6 +102,15 @@ $(document).ready(function() { equals(model.get('name'), ''); }); + test("Model: clear", function() { + var changed; + var model = new Backbone.Model({name : "Model"}); + model.bind("change:name", function(){ changed = true; }); + model.clear(); + equals(changed, true); + equals(model.get('name'), undefined); + }); + test("Model: changed, hasChanged, changedAttributes, previous, previousAttributes", function() { var model = new Backbone.Model({name : "Tim", age : 10}); model.bind('change', function() { @@ -153,6 +162,30 @@ $(document).ready(function() { equals(lastError, "Can't change admin status."); }); + test("Model: validate on unset and clear", function() { + var error; + var model = new Backbone.Model({name: "One"}); + model.validate = function(attrs) { + if ("name" in attrs) { + if (!attrs.name) { + error = true; + return "No thanks."; + } + } + }; + model.set({name: "Two"}); + equals(model.get('name'), 'Two'); + equals(error, undefined); + model.unset('name'); + equals(error, true); + equals(model.get('name'), 'Two'); + model.clear(); + equals(model.get('name'), 'Two'); + delete model.validate; + model.clear(); + equals(model.get('name'), undefined); + }); + test("Model: validate with error callback", function() { var lastError, boundError; var model = new Backbone.Model();