Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Child model and collection validators #203

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dist/backbone-validation-amd-min.js

Large diffs are not rendered by default.

24 changes: 23 additions & 1 deletion dist/backbone-validation-amd.js
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,9 @@
number: '{0} must be a number',
email: '{0} must be a valid email',
url: '{0} must be a valid url',
inlinePattern: '{0} is invalid'
inlinePattern: '{0} is invalid',
validModel: '{0} must be a validated model',
validCollection: '{0} must be a validated collection'
};

// Label formatters
Expand Down Expand Up @@ -627,6 +629,26 @@
if (!hasValue(value) || !value.toString().match(defaultPatterns[pattern] || pattern)) {
return this.format(defaultMessages[pattern] || defaultMessages.inlinePattern, this.formatLabel(attr, model), pattern);
}
},

// Model validator
// Validates that a (nested) model is valid as defined by it's own validations
validModel: function (value, attr, customValue, model) {
if (value && !value.isValid(true)) {
return this.format(defaultMessages.validModel, this.formatLabel(attr, model));
}
},

// Collection validator
// Validates that a (nested) collection of models is valid as defined by their own validations
validCollection: function (value, attr, customValue, model) {
var errors = value.map(function (entry) {
return entry.isValid(true);
});

if (_.indexOf(errors, false) !== -1) {
return this.format(defaultMessages.validCollection, this.formatLabel(attr, model));
}
}
};
}());
Expand Down
2 changes: 1 addition & 1 deletion dist/backbone-validation-min.js

Large diffs are not rendered by default.

24 changes: 23 additions & 1 deletion dist/backbone-validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,9 @@ Backbone.Validation = (function(_){
number: '{0} must be a number',
email: '{0} must be a valid email',
url: '{0} must be a valid url',
inlinePattern: '{0} is invalid'
inlinePattern: '{0} is invalid',
validModel: '{0} must be a validated model',
validCollection: '{0} must be a validated collection'
};

// Label formatters
Expand Down Expand Up @@ -620,6 +622,26 @@ Backbone.Validation = (function(_){
if (!hasValue(value) || !value.toString().match(defaultPatterns[pattern] || pattern)) {
return this.format(defaultMessages[pattern] || defaultMessages.inlinePattern, this.formatLabel(attr, model), pattern);
}
},

// Model validator
// Validates that a (nested) model is valid as defined by it's own validations
validModel: function (value, attr, customValue, model) {
if (value && !value.isValid(true)) {
return this.format(defaultMessages.validModel, this.formatLabel(attr, model));
}
},

// Collection validator
// Validates that a (nested) collection of models is valid as defined by their own validations
validCollection: function (value, attr, customValue, model) {
var errors = value.map(function (entry) {
return entry.isValid(true);
});

if (_.indexOf(errors, false) !== -1) {
return this.format(defaultMessages.validCollection, this.formatLabel(attr, model));
}
}
};
}());
Expand Down
116 changes: 58 additions & 58 deletions docs/backbone-validation.html

Large diffs are not rendered by default.

24 changes: 23 additions & 1 deletion src/backbone-validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,9 @@ Backbone.Validation = (function(_){
number: '{0} must be a number',
email: '{0} must be a valid email',
url: '{0} must be a valid url',
inlinePattern: '{0} is invalid'
inlinePattern: '{0} is invalid',
validModel: '{0} must be a validated model',
validCollection: '{0} must be a validated collection'
};

// Label formatters
Expand Down Expand Up @@ -613,6 +615,26 @@ Backbone.Validation = (function(_){
if (!hasValue(value) || !value.toString().match(defaultPatterns[pattern] || pattern)) {
return this.format(defaultMessages[pattern] || defaultMessages.inlinePattern, this.formatLabel(attr, model), pattern);
}
},

// Model validator
// Validates that a (nested) model is valid as defined by it's own validations
validModel: function (value, attr, customValue, model) {
if (value && !value.isValid(true)) {
return this.format(defaultMessages.validModel, this.formatLabel(attr, model));
}
},

// Collection validator
// Validates that a (nested) collection of models is valid as defined by their own validations
validCollection: function (value, attr, customValue, model) {
var errors = value.map(function (entry) {
return entry.isValid(true);
});

if (_.indexOf(errors, false) !== -1) {
return this.format(defaultMessages.validCollection, this.formatLabel(attr, model));
}
}
};
}());
Expand Down
60 changes: 60 additions & 0 deletions tests/validators/validCollection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
buster.testCase("validCollection validator", {
setUp: function() {
var that = this;
var ParentModel = Backbone.Model.extend({
validation: {
childCollection: {
validCollection: true
}
}
});
var ChildModel = Backbone.Model.extend({
validation: {
name: {
required: true
}
}
});
var ChildCollection = Backbone.Collection.extend({
model: ChildModel
});
var childCollection = new ChildCollection([{name:''}]);

Backbone.Validation.bind(new Backbone.View({collection: childCollection}));
this.model = new ParentModel({childCollection:childCollection});
this.view = new Backbone.View({
model: this.model
});

Backbone.Validation.bind(this.view, {
valid: this.spy(),
invalid: this.spy()
});
},

"has default error message for string": function(done) {
this.model.bind('validated:invalid', function(model, error){
assert.equals({childCollection: 'Child collection must be a validated collection'}, error);
done();
});
this.model.isValid(true);
},
"has valid childCollection": function() {
this.model.get("childCollection").first().set("name", "Steve");
assert(this.model.isValid(true));
},
"has valid childCollection with multiple items": function() {
this.model.get("childCollection").first().set("name", "Steve");
this.model.get("childCollection").add({name:"Amy"});
this.model.get("childCollection").add({name:"John"});
assert(this.model.isValid(true));
},
"has invalid childCollection": function() {
refute(this.model.isValid(true));
},
"has invalid childCollection with multiple items": function() {
this.model.get("childCollection").add({name:"Amy"});
this.model.get("childCollection").add({name:"John"});
refute(this.model.isValid(true));
}
});
50 changes: 50 additions & 0 deletions tests/validators/validModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
buster.testCase("validModel validator", {
setUp: function() {
var that = this;
var ParentModel = Backbone.Model.extend({
validation: {
childModel: {
validModel: true
}
}
});
var ChildModel = Backbone.Model.extend({
validation: {
name: {
required: true
}
}
});
this.childModel = new ChildModel();
this.childModel.set("name", '');
Backbone.Validation.bind(new Backbone.View({model: this.childModel})); // childModel requires a view for validation to work
this.model = new ParentModel({childModel:this.childModel});
this.view = new Backbone.View({
model: this.model
});

Backbone.Validation.bind(this.view, {
valid: this.spy(),
invalid: this.spy()
});
},

"has default error message for string": function(done) {
this.model.bind('validated:invalid', function(model, error){
assert.equals({childModel: 'Child model must be a validated model'}, error);
done();
});
this.model.isValid(true);
},
"has valid childModel": function() {
this.model.get("childModel").set("name", "Steve");
assert(this.model.isValid(true));
},
"has no childModel": function() {
this.model.set("childModel", null);
assert(this.model.isValid(true));
},
"has invalid childModel": function() {
refute(this.model.isValid(true));
}
});