This answer follows the approach of keeping jquery-validation outside of KO. I think this is OK, because you don't lose any magic; jquery-validation has its own framework for tracking changes and it keeps KO and jquery-validation separate, which is simple.
Here is your fiddle, with this approach applied:
http://jsfiddle.net/htqfa1qw/7/
The fixes were:
jquery-validation requires names in the input elements
These names then correspond with the keys in the rules object.
Param passing is weird and the docs don't explain it well!
So your rules object now looks like this:
EndDate: {
required: true,
dateGreater: {
param: "StartDate"
}
}
which is saying we want the <input name="EndDate">
to be greater than the <input name="StartDate">
We then modify the rule so that it gets the value directly from the DOM without needing to go via KO:
var start = new Date($("[name="+param+"]").val());
If you did want to do it via KO by passing in the observable as you describe, then you could do this:
http://jsfiddle.net/htqfa1qw/9/
Instantiate your data model before applying it:
var dm = new DataModel();
ko.applyBindings(dm);
Then alter the validation rule to lookup the method by the param, and call it:
$.validator.addMethod("dateGreater", function (endDate, element, param) {
var end= new Date(endDate);
var start = new Date(dm[param].call());
return this.optional(element) || start < end;
}, "Start Date must be less than End Date.");
(With ref to the comments) Once it is working with the bootstrap-datetime widget, you need to be careful about how the widget changes the input value, and how it's method of changing the value ineracts with both the jquery-validation framework and also the KO framework, both of which rely on change events.
In your fiddle the problem seems to be that jquery-validation gets triggered with the old date value before the widget successfully loads the new value into the input. Hence you see validation happening on the old value... The quick fix seems to be to call jquery-validation's valid() method, to trigger a manual validation, in the event handler you already have:
$el.datepicker(options).on("changeDate", function (ev) {
var observable = valueAccessor();
observable(ev.date);
$(this).datepicker('hide');
// Poke jquery validation to validate this new value.
$("#date-form").valid();
});
Demo here:
http://jsfiddle.net/htqfa1qw/12/
In this fiddle there's some console.logs and you can track the sequence:
- validation is called with the old value (the "Start date..." log statement)
- your event handler kicks in with the new value (the "changeDate" log statement)
- We manually call valid() and validation is called with the new value (the 2nd "Start date..." log statement)