Reputation: 4020
I'm using Knockout for a View bound to a ViewModel with some depth/complexity to it.
To validate my ViewModel i need to compute across the entire VM tree (walking & comparing descendants). I was hoping to leverage the knockout-validation plugin @ https://github.com/ericmbarnard/Knockout-Validation to create some arbitrary custom validation rule and report any errors.
I set up one possible approach using a KO computed observable @ http://jsfiddle.net/drdamour/ZrVZ7/ . The validation rule is to make sure no 2 SubCollections have the same value. This is working, but it's not using Knockout-Validation and my rule is now implemented in my computed observable which seems wrong.
My question is very similar to Knockout Validation validatedObservable group error but i find the discovered solution (hosted at http://jsfiddle.net/CGuW2/6/) to be less than ideal:
var viewModel = {
num1: ko.observable("50").extend({ number: true, min: 0, max: 100 }),
num2: ko.observable("50").extend({ number: true, min: 0, max: 100 })
};
viewModel.isValidSum = ko.validatedObservable({
num1: viewModel.num1,
num2: viewModel.num2
}).extend({ mustEqual: 100 });
ko.applyBindings(viewModel);
as it's duplicating the ViewModel by adding it's validated self as a property to itself (isValidSum). I tried to eliminate this redundancy @ http://jsfiddle.net/drdamour/5B8s4/ but the view fails to bind to the validatedObservable:
var viewModel = {
num1: ko.observable("50").extend({ number: true, min: 0, max: 100 }),
num2: ko.observable("50").extend({ number: true, min: 0, max: 100 })
};
var vm = ko.validatedObservable(viewModel).extend({ mustEqual: 101 });
ko.applyBindings(vm);
This may be a bug with KO or KO-Validation, or i may just be doing it totally wrong.
So the question is: what's the best way in knockout to determine if a VM is valid against a condition that evaluates across multiple properties & layers of the VM?
Upvotes: 2
Views: 4541
Reputation: 13672
I avoid this wagon circling by taking a different approach to validating my models by grouping
the observables I want to validate on the model:
This is some init code used to set my stage (you can take a look at all the options available Here:
ko.validation.init({
registerExtenders: true,
parseInputAttributes: true,
grouping: { deep: true, observable: false }
});
then I would setup your model like so:
function testModel() {
var self = this;
self.num1 = ko.observable(100).extend({ number: true, min: 0, max: 100 });
self.num2 = ko.observable(50).extend({ number: true, min: 0, max: 100 });
self.sum = ko.observable(150).extend({ number: true, equal: 100 });
self.num1.subscribe(function () {
self.sum(self.num1() + self.num2());
});
self.num2.subscribe(function () {
self.sum(self.num1() + self.num2());
});
self.errors = ko.validation.group(this);
}
var viewModel = new ViewModel();
//somewhere later where we are testing the model
if (viewModel.sum.isValid())
//YAY!!!
else
//this will update the UI as you have configured it to show the error messages
viewModel.errors.showAllMessages();
using ko.validation.group(model)
will cause validation to traverse through all the observables in your model (how deep, depends on the initial settings, you'll note I made mine grouping: { deep: true }
which means if there are sub models w/observables inside this model it would validate those as well.
You can do this not only with the entire model but portions of it as well if you want to isolate different validation cases.
EDIT:
Here is an approach to meet your requirements that does work. It's not ideal to have to subscribe to all the observables that you want to validate against a condition but your only alternative is to simply group them into a validatedObservable which means a most likely preferred structure to your data.
Upvotes: 4