Skip to content

Commit

Permalink
Merge pull request #59 from davewasmer/enumerable-errors
Browse files Browse the repository at this point in the history
Add enumerable list of all error objects
  • Loading branch information
offirgolan committed Oct 23, 2015
2 parents 8c8c682 + 23eb2b9 commit cc315ef
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 7 deletions.
6 changes: 6 additions & 0 deletions addon/validations/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Ember from 'ember';

export default Ember.Object.extend({
attribute: null,
message: null
});
21 changes: 19 additions & 2 deletions addon/validations/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,23 @@ function createGlobalValidationProps(validatableAttrs) {
return get(this, 'messages.0');
}));


props.errors = computed(...validatableAttrs.map((attr) => `attrs.${attr}.@each.errors`), function() {
var errors = [];
validatableAttrs.forEach((attr) => {
var validation = get(this, `attrs.${attr}`);
if (validation) {
errors.push(get(validation, 'errors'));
}
});

return emberArray(flatten(errors)).compact();
});

props.error = computed('errors.[]', cycleBreaker(function() {
return get(this, 'errors.0');
}));

return props;
}

Expand All @@ -138,10 +155,10 @@ function createGlobalValidationProps(validatableAttrs) {
function createMixin(GlobalValidations, AttrValidations) {
return Ember.Mixin.create({
validate() {
return this.get('validations').validate(...arguments);
return get(this, 'validations').validate(...arguments);
},
validateSync() {
return this.get('validations').validateSync(...arguments);
return get(this, 'validations').validateSync(...arguments);
},
validations: computed(function() {
return GlobalValidations.create({
Expand Down
21 changes: 17 additions & 4 deletions addon/validations/result-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,30 @@ export default Ember.Object.extend({
return uniq(compact(messageArray));
})),

message: computed('messages.[]', cycleBreaker(function() {
return get(this, 'messages.0');
})),

errors: computed('content.@each.{error,errors}', cycleBreaker(function() {
let errors = [
get(this, 'content').getEach('error'),
get(this, 'content').getEach('errors')
];
let errorArray = flatten(errors);
return uniq(compact(errorArray));
})),

error: computed('errors.[]', cycleBreaker(function() {
return get(this, 'errors.0');
})),

_promise: computed('content.@each._promise', cycleBreaker(function() {
var promises = get(this, 'content').getEach('_promise');
if (!isEmpty(promises)) {
return RSVP.all(compact(flatten(promises)));
}
})),

message: computed('messages.[]', cycleBreaker(function() {
return get(this, 'messages.0');
})),

value: computed('isAsync', cycleBreaker(function() {
var isAsync = get(this, 'isAsync');
var promise = get(this, '_promise');
Expand Down
14 changes: 14 additions & 0 deletions addon/validations/result.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import Ember from 'ember';
import ValidationResultCollection from './result-collection';
import ValidationError from './error';
import { hasEmberData } from '../utils/utils';

const {
Expand Down Expand Up @@ -68,6 +69,17 @@ var ValidationsObject = Ember.Object.extend({
}
}
return !isNone(attrValue);
}),

error: computed('message', 'isInvalid', 'attribute', function() {
if (get(this, 'isInvalid')) {
return ValidationError.create({
message: get(this, 'message'),
attribute: get(this, 'attribute')
});
} else {
return null;
}
})
});

Expand All @@ -84,6 +96,8 @@ export default Ember.Object.extend({
isDirty: computed.oneWay('_validations.isDirty'),
message: computed.oneWay('_validations.message'),
messages: computed.oneWay('_validations.messages'),
error: computed.oneWay('_validations.error'),
errors: computed.oneWay('_validations.errors'),

// This hold all the logic for the above CPs. We do this so we can easily switch this object out with a different validations object
_validations: computed('model', 'attribute', '_promise', function() {
Expand Down
29 changes: 28 additions & 1 deletion docs/docs/validating.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ model.validate({
```

# Inspecting Validations
All validations can be accessed via the `validations` object created on your model/object. Each attribute also has its own validation which has the same properties. An attribute validation can be accessed via `validations.attrs.<ATTRIBUTE>`. If you want to use [Ember Data's Errors API](http://emberjs.com/api/data/classes/DS.Errors.html), check out their docs on how to access everything you might need.
All validations can be accessed via the `validations` object created on your model/object. Each attribute also has its own validation which has the same properties. An attribute validation can be accessed via `validations.attrs.<ATTRIBUTE>`. If you want to use [Ember Data's Errors API](http://emberjs.com/api/data/classes/DS.Errors.html), check out their docs on how to access everything you might need.

**isValid**
```javascript
Expand Down Expand Up @@ -110,3 +110,30 @@ An alias to the first message in the messages collection.
get(user, 'validations.message')
get(user, 'validations.attrs.username.message')
```

**errors**

A collection of all errors on the object in question. Each error object includes the error message and it's associated attribute name.

```javascript
// Example
get(user, 'validations.errors')
/* [
* {
* attribute: 'email'
* messages: "Can't be blank"
* },
* {
* ...
* }
* ]
*/
```

**error**
An alias to the first error in the errors collection.

```javascript
// Example
get(user, 'validations.error')
```
8 changes: 8 additions & 0 deletions tests/unit/validations/factory-general-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ test("basic sync validation – invalid", function(assert) {
assert.equal(object.get('validations.attrs.lastName.isValidating'), false);
assert.equal(object.get('validations.attrs.lastName.message'), 'lastName should be present');

assert.equal(object.get('validations.errors.length'), 2, 'errors length was expected to be 2');
assert.ok(object.get('validations.errors').indexOf(object.get('validations.attrs.firstName.errors.0')) > -1, 'errors was expected to contain firstName error');
assert.ok(object.get('validations.errors').indexOf(object.get('validations.attrs.lastName.errors.0')) > -1, 'errors was expected to contain lastName error');
assert.equal(object.get('validations.errors.0.attribute'), 'firstName', 'error object was expected to have attribute "firstName"');
assert.equal(object.get('validations.errors.1.attribute'), 'lastName', 'error object was expected to have attribute "lastName"');

object.set('firstName', 'stef');
object.set('lastName', 'penner');

Expand All @@ -69,6 +75,8 @@ test("basic sync validation – invalid", function(assert) {
assert.equal(object.get('validations.attrs.lastName.isValid'), true);
assert.equal(object.get('validations.attrs.lastName.isValidating'), false);
assert.equal(object.get('validations.attrs.lastName.message'), null);

assert.equal(object.get('validations.errors.length'), 0, 'errors length was expected to be 0');
});

test("basic sync validation - valid", function(assert) {
Expand Down

0 comments on commit cc315ef

Please sign in to comment.