Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Run observable validations when observable change.

* Also adds a configuration to allow the validation to run only on input
changes, if desired.
  • Loading branch information...
commit e3ddc016db6aebf4f5f2a6f658bd807376e9b3c5 1 parent 398ca74
Luiz Ribeiro luizfar authored
13 spec/computed-observable-spec.js
View
@@ -5,8 +5,8 @@ describe('Computed observable validation', function () {
var html;
viewModel = {};
- viewModel.firstName = ko.observable('');
- viewModel.lastName = ko.observable('');
+ viewModel.firstName = ko.observable('First');
+ viewModel.lastName = ko.observable('Last');
viewModel.fullName = ko.computed(function () {
if (viewModel.firstName() || viewModel.lastName()) {
return viewModel.firstName() + viewModel.lastName();
@@ -30,12 +30,21 @@ describe('Computed observable validation', function () {
it('fails if the computed value is not valid after one of its dependencies change', function () {
$('#firstName').val('').trigger('change');
+ expect(viewModel.fullName.isValid()).toBe(true);
+
+ $('#lastName').val('').trigger('change');
+
expect(viewModel.fullName()).toBe('');
expect(viewModel.fullName.isValid()).toBe(false);
expect(viewModel.fullName.validationMessage()).toBe('Full Name is required.');
});
it('succeeds if the computed value is valid after one of its dependencies change', function () {
+ $('#firstName').val('').trigger('change');
+ $('#lastName').val('').trigger('change');
+
+ expect(viewModel.fullName.isValid()).toBe(false);
+
$('#firstName').val('John').trigger('change');
expect(viewModel.fullName()).toBe('John');
4 spec/integration-spec.js
View
@@ -29,7 +29,7 @@ describe('ko validation integration', function () {
};
viewModel = {
- requiredField: ko.observable('').extend({
+ requiredField: ko.observable('First Name').extend({
'required': ['First Name is required.']
}),
equalField: ko.observable(''),
@@ -66,7 +66,7 @@ describe('ko validation integration', function () {
isItRequired: ko.observable(true)
};
- viewModel.sometimesRequired = ko.observable('').extend({
+ viewModel.sometimesRequired = ko.observable('Sometimes').extend({
'onlyIf': [viewModel.isItRequired, { 'required': [ 'Sometimes' ] }]
});
44 spec/observable-spec.js
View
@@ -25,6 +25,50 @@ describe('observables validation', function () {
expect(observable.validationState()).toBe(ko.validation.validationStates.INVALID);
});
+ it('runs the validation when the observable value changes', function () {
+ var observable;
+ observable = ko.observable().extend({ 'required': ['Field is required.'] });
+
+ observable('value');
+ expect(observable.isValid()).toBe(true);
+
+ observable('');
+ expect(observable.isValid()).toBe(false);
+ });
+
+ describe('when the observable is to be validated only on input changes', function () {
+ var observable, viewModel;
+
+ beforeEach(function () {
+ observable = ko.observable('Value').extend({
+ required: ['Value is required'],
+ validatesOn: 'inputChange'
+ });
+
+ viewModel = { obs: observable };
+
+ setFixtures('<div id="parent"><input id="input" data-bind="value: obs"/></div>');
+ ko.applyBindings(viewModel, $('#parent')[0]);
+ });
+
+ it('does not validate when the observable changes', function () {
+ expect(observable.isValid()).toBe(true);
+
+ observable('');
+
+ expect(observable.isValid()).toBe(true);
+ });
+
+ it('validates when the input changes', function () {
+ expect(observable.isValid()).toBe(true);
+
+ $('#input').val('').trigger('change');
+
+ expect(observable.isValid()).toBe(false);
+ expect(observable.validationMessage()).toBe('Value is required');
+ });
+ });
+
describe('validating an input', function () {
var observable, viewModel;
2  spec/validation-element-spec.js
View
@@ -3,7 +3,7 @@ describe('Validation message element', function () {
beforeEach(function () {
viewModel = {
- firstName: ko.observable('').extend({
+ firstName: ko.observable('name').extend({
'required': ['First Name is required.'],
'maxLength': [10, 'Up to 10 chars, please.']
})
28 src/ko-validation.js
View
@@ -105,6 +105,12 @@ ko.validation.registerValidator = function (name, validatorFactory) {
observable.isValid = ko.computed(function () {
return observable.validationState() !== ko.validation.validationStates.INVALID;
});
+ if (observable.__validatesOn__ !== 'inputChange') {
+ observable.__validatesOn__ = 'change';
+ observable.__validationSubscription__ = observable.subscribe(function () {
+ ko.validation.utils.runValidations(observable);
+ });
+ }
}
validator = ko.validation.utils.createValidator(name, param);
@@ -153,11 +159,12 @@ ko.validation.registerValidator = function (name, validatorFactory) {
}
function initValidationFor(inputElement, observable) {
- bindEventListenerToRunValidation(inputElement, observable);
-
- var subscription = observable.validationState.subscribe(function () {
+ if (observable.__validatesOn__ === 'inputChange') {
+ bindEventListenerToRunValidation(inputElement, observable);
+ }
+ var messageSubscription = observable.validationState.subscribe(function () {
if (observable.__hasCustomValidationElement__) {
- subscription.dispose();
+ messageSubscription.dispose();
return;
}
var validationElement = insertOrGetMessageElementAt(inputElement.parentNode);
@@ -165,10 +172,21 @@ ko.validation.registerValidator = function (name, validatorFactory) {
});
ko.utils.domNodeDisposal.addDisposeCallback(inputElement, function () {
- subscription.dispose();
+ messageSubscription.dispose();
});
}
+ ko.extenders.validatesOn = function (observable, eventName) {
+ if (eventName !== 'change' && eventName !== 'inputChange') {
+ throw new Error('Observable can be validated only on events "change" or "inputChange".');
+ }
+ observable.__validatesOn__ = eventName;
+ if (eventName === 'inputChange' && observable.__validationSubscription__) {
+ observable.__validationSubscription__.dispose();
+ }
+ return observable;
+ };
+
ko.extenders.validatesAfter = function (observable, dependentObservables) {
ko.utils.arrayForEach(dependentObservables, function (dependentObservable) {
dependentObservable.__validates__ = dependentObservable.__validates__ || [];
Please sign in to comment.
Something went wrong with that request. Please try again.