From a2bb8846b431347388fa7244ed65fa4bd8bcad4e Mon Sep 17 00:00:00 2001 From: Aaron Renoir Date: Tue, 13 Oct 2015 19:31:13 -0700 Subject: [PATCH] fix transitioning into invalid state remove events from error class add functionality to become valid if errors are removed depricate adding errors change deprecations to regular warnings --- .../ember-data/lib/system/model/errors.js | 93 ++++++++++++++++--- .../lib/system/model/internal-model.js | 13 ++- packages/ember-data/lib/system/model/model.js | 3 +- .../ember-data/lib/system/model/states.js | 8 ++ .../tests/integration/records/save-test.js | 12 ++- 5 files changed, 110 insertions(+), 19 deletions(-) diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 2c1ffda2d24..bba43881b73 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -99,12 +99,31 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @param {Object} target @param {Function} becameInvalid @param {Function} becameValid + @deprecated */ registerHandlers: function(target, becameInvalid, becameValid) { + Ember.deprecate( + `Record errors will no longer be evented.`, false, { + id: 'ds.errors.registerHandlers', + until: '3.0.0' + }); + + this._registerHandlers(target, becameInvalid, becameValid); + }, + + + /** + Register with target handler + + @method _registerHandlers + @private + */ + _registerHandlers: function(target, becameInvalid, becameValid) { this.on('becameInvalid', target, becameInvalid); this.on('becameValid', target, becameValid); }, + /** @property errorsByAttributeName @type {Ember.MapWithDefault} @@ -206,19 +225,35 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method add @param {String} attribute @param {(Array|String)} messages + @deprecated */ add: function(attribute, messages) { + Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.add' + }); + var wasEmpty = get(this, 'isEmpty'); + this._add(attribute, messages); + + if (wasEmpty && !get(this, 'isEmpty')) { + this.trigger('becameInvalid'); + } + }, + + + /** + Adds error messages to a given attribute without sending event. + + @method _add + @private + */ + _add: function(attribute, messages) { messages = this._findOrCreateMessages(attribute, messages); this.addObjects(messages); get(this, 'errorsByAttributeName').get(attribute).addObjects(messages); this.notifyPropertyChange(attribute); - - if (wasEmpty && !get(this, 'isEmpty')) { - this.trigger('becameInvalid'); - } }, /** @@ -269,8 +304,29 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method remove @param {String} attribute + @deprecated */ remove: function(attribute) { + Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.remove' + }); + + if (get(this, 'isEmpty')) { return; } + + this._remove(attribute); + + if (get(this, 'isEmpty')) { + this.trigger('becameValid'); + } + }, + + /** + Removes all error messages from the given attribute without sending event. + + @method _remove + @private + */ + _remove: function(attribute) { if (get(this, 'isEmpty')) { return; } let content = this.rejectBy('attribute', attribute); @@ -278,10 +334,6 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { get(this, 'errorsByAttributeName').delete(attribute); this.notifyPropertyChange(attribute); - - if (get(this, 'isEmpty')) { - this.trigger('becameValid'); - } }, /** @@ -304,8 +356,28 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { ``` @method clear + @deprecated */ clear: function() { + Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.clear' + }); + + if (get(this, 'isEmpty')) { return; } + + this._clear(); + this.trigger('becameValid'); + }, + + + /** + Removes all error messages. + to the record. + + @method _clear + @private + */ + _clear: function() { if (get(this, 'isEmpty')) { return; } let errorsByAttributeName = get(this, 'errorsByAttributeName'); @@ -320,11 +392,10 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this.notifyPropertyChange(attribute); }, this); - this._super(); - - this.trigger('becameValid'); + Ember.ArrayProxy.prototype.clear.call(this); }, + /** Checks if there is error messages for the given attribute. diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index b10e0f3e38e..bfa06b86db8 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -616,17 +616,24 @@ InternalModel.prototype = { addErrorMessageToAttribute: function(attribute, message) { var record = this.getRecord(); - get(record, 'errors').add(attribute, message); + get(record, 'errors')._add(attribute, message); }, removeErrorMessageFromAttribute: function(attribute) { var record = this.getRecord(); - get(record, 'errors').remove(attribute); + get(record, 'errors')._remove(attribute); }, clearErrorMessages: function() { var record = this.getRecord(); - get(record, 'errors').clear(); + get(record, 'errors')._clear(); + }, + + hasErrors: function() { + var record = this.getRecord(); + var errors = get(record, 'errors'); + + return !Ember.isEmpty(errors); }, // FOR USE DURING COMMIT PROCESS diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 1438005ceb9..715a2efa538 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -354,14 +354,13 @@ var Model = Ember.Object.extend(Ember.Evented, { errors: Ember.computed(function() { let errors = Errors.create(); - errors.registerHandlers(this._internalModel, + errors._registerHandlers(this._internalModel, function() { this.send('becameInvalid'); }, function() { this.send('becameValid'); }); - return errors; }).readOnly(), diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index b71684c3e27..40dae6a55c4 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -323,6 +323,10 @@ var DirtyState = { internalModel.removeErrorMessageFromAttribute(context.name); didSetProperty(internalModel, context); + + if (!internalModel.hasErrors()) { + this.becameValid(internalModel); + } }, becameInvalid: Ember.K, @@ -695,6 +699,10 @@ var RootState = { internalModel.removeErrorMessageFromAttribute(context.name); didSetProperty(internalModel, context); + + if (!internalModel.hasErrors()) { + this.becameValid(internalModel); + } }, becameInvalid: Ember.K, diff --git a/packages/ember-data/tests/integration/records/save-test.js b/packages/ember-data/tests/integration/records/save-test.js index 46bab32edf5..05a3d2ec1c7 100644 --- a/packages/ember-data/tests/integration/records/save-test.js +++ b/packages/ember-data/tests/integration/records/save-test.js @@ -51,7 +51,9 @@ test("Will reject save on error", function() { }); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.reject(); + var error = new DS.InvalidError([{ title: 'not valid' }]); + + return Ember.RSVP.reject(error); }; run(function() { @@ -70,8 +72,10 @@ test("Retry is allowed in a failure handler", function() { var count = 0; env.adapter.createRecord = function(store, type, snapshot) { + var error = new DS.InvalidError([{ title: 'not valid' }]); + if (count++ === 0) { - return Ember.RSVP.reject(); + return Ember.RSVP.reject(error); } else { return Ember.RSVP.resolve({ id: 123 }); } @@ -174,7 +178,9 @@ test("Will reject save on invalid", function() { }); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.reject({ title: 'invalid' }); + var error = new DS.InvalidError([{ title: 'not valid' }]); + + return Ember.RSVP.reject(error); }; run(function() {