From 0057b0435f1f484b20d93f1db4ea88c26d3f4b17 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 --- addon/system/model/errors.js | 93 +++++++++++++++++++++++--- addon/system/model/internal-model.js | 13 +++- addon/system/model/model.js | 3 +- addon/system/model/states.js | 8 +++ tests/integration/records/save-test.js | 12 +++- 5 files changed, 110 insertions(+), 19 deletions(-) diff --git a/addon/system/model/errors.js b/addon/system/model/errors.js index 415fcf9407c..1d11f6e0a60 100644 --- a/addon/system/model/errors.js +++ b/addon/system/model/errors.js @@ -107,12 +107,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} @@ -214,19 +233,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'); - } }, /** @@ -277,8 +312,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); @@ -286,10 +342,6 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { get(this, 'errorsByAttributeName').delete(attribute); this.notifyPropertyChange(attribute); - - if (get(this, 'isEmpty')) { - this.trigger('becameValid'); - } }, /** @@ -312,8 +364,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'); @@ -328,11 +400,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/addon/system/model/internal-model.js b/addon/system/model/internal-model.js index 13d47f608c2..1f4b30746b4 100644 --- a/addon/system/model/internal-model.js +++ b/addon/system/model/internal-model.js @@ -676,17 +676,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/addon/system/model/model.js b/addon/system/model/model.js index bfa760cd6fb..dcc5a8bccdc 100644 --- a/addon/system/model/model.js +++ b/addon/system/model/model.js @@ -351,14 +351,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/addon/system/model/states.js b/addon/system/model/states.js index f6fae3a4df0..e4c0cb9997a 100644 --- a/addon/system/model/states.js +++ b/addon/system/model/states.js @@ -326,6 +326,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/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index 748d375537f..a8e09a5ce82 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -58,7 +58,9 @@ test("Will reject save on error", function(assert) { }); 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() { @@ -77,8 +79,10 @@ test("Retry is allowed in a failure handler", function(assert) { 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 }); } @@ -181,7 +185,9 @@ test("Will reject save on invalid", function(assert) { }); 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() {