Skip to content

Commit

Permalink
Merge pull request #3853 from arenoir/invalid-state-fix
Browse files Browse the repository at this point in the history
fix transitioning into invalid state
  • Loading branch information
bmac committed Nov 30, 2015
2 parents 9a1609a + 0057b04 commit b6242fc
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 19 deletions.
93 changes: 82 additions & 11 deletions addon/system/model/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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');
}
},

/**
Expand Down Expand Up @@ -277,19 +312,36 @@ 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);
set(this, 'content', content);
get(this, 'errorsByAttributeName').delete(attribute);

this.notifyPropertyChange(attribute);

if (get(this, 'isEmpty')) {
this.trigger('becameValid');
}
},

/**
Expand All @@ -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');
Expand All @@ -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.
Expand Down
13 changes: 10 additions & 3 deletions addon/system/model/internal-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions addon/system/model/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(),

Expand Down
8 changes: 8 additions & 0 deletions addon/system/model/states.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ var DirtyState = {
internalModel.removeErrorMessageFromAttribute(context.name);

didSetProperty(internalModel, context);

if (!internalModel.hasErrors()) {
this.becameValid(internalModel);
}
},

becameInvalid: Ember.K,
Expand Down Expand Up @@ -695,6 +699,10 @@ var RootState = {
internalModel.removeErrorMessageFromAttribute(context.name);

didSetProperty(internalModel, context);

if (!internalModel.hasErrors()) {
this.becameValid(internalModel);
}
},

becameInvalid: Ember.K,
Expand Down
12 changes: 9 additions & 3 deletions tests/integration/records/save-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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 });
}
Expand Down Expand Up @@ -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() {
Expand Down

0 comments on commit b6242fc

Please sign in to comment.