Knockout gives you a slick way to do real-time validation on your data with its built-in extenders. At first glance, it may not seem like an entirely intuitive process, but it’s actually pretty clever. When you use an extender, you’re extending the property to have additional sub-properties and behaviors. Makes sense, right?
Let’s look at a simple example: validating a date value.
We begin by creating a simple view model and UI.
var viewModel = function () { var self = this; this.dateValue = ko.observable(); }; ko.applyBindings(new viewModel());
<div> <input data-bind="value: dateValue" /> </div>
Now we can create our extender. We introduce a new hasError property that we’ll bind to the UI and use to show & hide validation messages. There’s a validate function that contains the validation logic. The validate method is called to perform the initial validation, and subscribe is called so that validate will be called when the value changes. Note that we also add valueUpdate: ‘afterkeydown’ to the input data-binding. This allows the validation to perform after each keystroke.
var viewModel = function () { var self = this; this.dateValue = ko.observable().extend({ validDate: true }); }; ko.extenders.validDate = function (target) { target.hasError = ko.observable(); function validate(value) { var invalid = isNaN(Date.parse(value)); target.hasError(invalid); } validate(target()); target.subscribe(validate); return target; }; ko.applyBindings(new viewModel());
<div> <input data-bind="value: dateValue, valueUpdate: 'afterkeydown'" /> <span data-bind="visible: dateValue.hasError">Invalid!</span> </div>
That’s it for the hard stuff. All that’s left is to figure out what should be shown or hidden when the value is invalid or valid. I chose to show an alert icon and added some CSS to make the input box red.
.invalid input { border: 1px solid red; } .ui-icon { display: inline-block; vertical-align: middle; }
<div data-bind="css: { invalid: dateValue.hasError }"> <input data-bind="value: dateValue, valueUpdate: 'afterkeydown'" /> <span class="ui-icon ui-icon-alert" title="Invalid value" data-bind="visible: dateValue.hasError"></span> </div>
Check out this Fiddle for the working example.