I am using this plugin https://github.com/ericmbarnard/Knockout-Validation and i am trying to validate an object that is loaded dynamically.
Javascript:
function VM() {
var self = this;
// This is a static observable, just to ensure that basic validation works fine.
self.static = ko.observable();
self.static.extend({required: true});
// This is the observable that will be updated to my model instance.
self.person = ko.observable({});
// This is an handler for manual trigger.
// I'm not even sure this is needed.
self.a = function(){
self.errors.showAllMessages();
self.staticErrors.showAllMessages();
}
// Here i'm loading current person from somewhere, i.e. a rest service.
self.load = function() {
// Update observable
self.person(new Model());
// Define validation rules
self.person().name.extend({required: true});
self.person().email.extend({required: true});
// Set person data
self.person().name('Long');
self.person().email('John');
// Set validators
self.errors = ko.validation.group(self.person);
self.staticErrors = ko.validation.group(self.static);
}
}
// Just a test model.
function Model() {
this.name = ko.observable();
this.email = ko.observable();
}
ko.validation.init();
var vm = new VM();
ko.applyBindings(vm);
Markup
<ul>
<li>1. Hit "Load"</li>
<li>2. Hit "Show errors", or maunally change input data.</li>
</ul>
<button data-bind='click: load'>Load</button>
<br/>
<h1>This is working properly.</h1>
<input type='text' data-bind='value: static' />
<br/>
<h1>This is not working.</h1>
<input type='text' data-bind='value: person().name' />
<input type='text' data-bind='value: person().email' />
<br/>
<button data-bind='click: a'>Show errors</button>
Fiddle http://jsfiddle.net/qGzfr/
How do I make this work?
The validation plugin only gets applied in your bindings only if by the time when the binding is parsed by Knockout your properties are validate.
In different words: you cannot add validation to a property after the property was bound on the UI.
In your example you are using an empty object in
self.person = ko.observable({});
as a default value, so when Knockout executes thedata-bind='value: person().name'
expression you don't have aname
property so the validation won't work even if you later add thename
property to your object.In your example you can solve this with changing your
Model
constructor to include the validation rules:And use an empty
Model
object as the default person:And when calling
Load
don't replace theperson
object but update its properties:Demo JSFiddle.
Note: Knockout does not always handles well if you replace whole object like
self.person(new Model());
so it is anyway a better practice to only update the properties and not throw away the whole object.A different solution would be to use the
with
binding because inside thewith
binding KO will reevaluate the bindings if the bound property changes.So change your view:
In this case you need to use
null
as the defaultperson
:And in your
Load
you need to add the validation before assigning yourperson
property so by the time KO applies the bindings your properties have the validation:Demo JSFiddle.