Reputation: 16501
I'm using the Backbone Validation plugin and would like to selectively validate different sets of model attributes at different times, is this possible?
My test model has validation for name
, age
and address
and if I wanted to validate only address
, how would I do this?
I thought it was a case of calling this.model.validate('address');
but all the validation rules seem to run?
JS
console.clear();
const Model = Backbone.Model.extend({
validation: {
name: {
required: true
},
age: {
range: [1, 80],
required: true
},
address: {
minLength: 1,
msg: 'Address required',
required: false
}
}
});
const View = Backbone.View.extend({
template: Handlebars.compile( $('.tmpl-person').html() ),
className: 'view',
events: {
'click .js-action--validate-keys': 'actionValidateKeysClicked',
'click .js-action--validate-key': 'actionValidateKeyClicked'
},
initialize() {
Backbone.Validation.bind(this);
this.listenTo(this.model, 'validated', this.onModelValidated, this);
this.listenTo(this.model, 'validated:valid', this.onModelValid, this);
this.listenTo(this.model, 'validated:invalid', this.onModelInvalid, this);
},
render() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
actionValidateKeysClicked(event) {
event.preventDefault();
console.log('actionValidateKeysClicked');
this.model.set({
'name': 'Joe Bloggs',
'age': 23
});
this.model.validate(['name', 'age']);
},
actionValidateKeyClicked(event) {
event.preventDefault();
console.log('actionValidateKeyClicked');
this.model.set('address', '123 ABC');
this.model.validate('address');
},
/**
* The validated event is triggered after validation is performed, either it was successful or not.
* isValid is true or false depending on the result of the validation.
*/
onModelValidated(isValid, model, errors) {
console.log('onModelValidated', isValid, model, errors);
},
onModelValid(model) {
console.log('onModelValid', model);
},
onModelInvalid(model, errors) {
console.log('onModelInvalid', model, errors);
}
});
const newModel = new Model();
const newView = new View({
model: newModel
});
document.body.append(newView.render().el);
JSfiddle http://jsfiddle.net/kyllle/qmx2y9yr/
Upvotes: 1
Views: 775
Reputation: 17430
isValid
To validate only certain fields, Backbone.Validation offers a modified version of isValid
.
If you pass the name of an attribute or an array of names, you can check whether or not the attributes are valid:
// Check if name is valid var isValid = model.isValid('name'); // Check if name and age are valid var isValid = model.isValid(['name', 'age']);
isValid
will trigger an 'invalid'
event (source) only if there's an error with the validation, and won't trigger a 'validated'
event or a 'validated:valid'
.
preValidate
Sometimes it can be useful to check (for instance on each key press) if the input is valid - without changing the model - to perform some sort of live validation. You can execute the set of validators for an attribute, or a hash of attributes, by calling the
preValidate
method and pass it the name of the attribute and the value to validate, or a hash of attributes.If the value is not valid, the error message is returned (truthy), otherwise it returns a falsy value.
// Validate one attribute // The `errorsMessage` returned is a string var errorMessage = model.preValidate('attributeName', 'Value'); // Validate a hash of attributes // The errors object returned is a key/value pair of attribute name/error, e.g // { // name: 'Name is required', // email: 'Email must be a valid email' // } var errors = model.preValidate({name: 'value', email: '[email protected]'});
I took your code and made a small example below to demonstrate that the invalid event is not triggered when using isValid
, but it is trigger when using validate
. Also, note that no events are triggered with preValidate
.
const Model = Backbone.Model.extend({
validation: {
name: {
required: true
},
age: {
range: [1, 80],
required: true
},
address: {
minLength: 1,
msg: 'Address required',
required: true
}
}
});
const View = Backbone.View.extend({
template: $('.tmpl-person').html(),
className: 'view',
events: {
'click .validate': 'onValidateClick',
'click .is-valid': 'onIsValidClick',
'click .pre-validate': 'onPreValidateClick',
},
initialize() {
Backbone.Validation.bind(this);
this.listenTo(this.model, {
'all': this.onAllModelEvent,
// 'validated': this.onModelValidated,
// 'validated:valid': this.onModelValid,
// 'validated:invalid': this.onModelInvalid
});
},
render() {
this.$el.html(this.template);
this.$checkbox = this.$('.invalid');
return this;
},
getAddress() {
return this.$checkbox.is(':checked') ? null : '123 ABC';
},
onValidateClick() {
console.log('validate click');
this.model.set('address', this.getAddress());
console.log("validate:", this.model.validate('address'));
},
onIsValidClick() {
console.log('isValid click');
this.model.set('address', this.getAddress());
console.log("isValid:", this.model.isValid('address'));
},
onPreValidateClick() {
console.log('preValidate click');
this.model.set('address', this.getAddress());
console.log("preValidate:", this.model.preValidate('address'));
},
onAllModelEvent: function(event) {
console.log("event:", event);
}
});
const newModel = new Model();
const newView = new View({
model: newModel
});
document.body.append(newView.render().el);
* {
-webkit-font-smoothing: antialiased;
}
body {
padding: 5%;
font-size: 16px;
line-height: 1.4;
}
.view {
width: 100%;
height: 100vh;
background: lightBlue;
}
.btn {
outline: none;
border: none;
background: #1C90F3;
border-radius: 4px;
color: white;
padding: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.validation/0.11.5/backbone-validation-min.js"></script>
<script type="text/template" class="tmpl-person">
Set 'address' and use:
<button type="button" class="btn validate">validate</button>
<button type="button" class="btn is-valid">isValid</button>
<button type="button" class="btn pre-validate">preValidate</button>
<br>
<input type="checkbox" class="invalid">make address invalid.
</script>
Notice how I used listenTo
with an object instead of calling it 3 times.
this.listenTo(this.model, {
'validated': this.onModelValidated,
'validated:valid': this.onModelValid,
'validated:invalid': this.onModelInvalid
});
Also, there's no this
argument to pass to listenTo
, It's probably a confusion with the old on
/bind
syntax.
Upvotes: 1