There is already a library for doing validation in Knockout, aply named Knockout-Validation. I don't really remember what issues I ran into when I used it so long ago, but I remember giving up on it. It also doesn't appear to play well with RequireJS, which is critical if you work in Durandal as I do.

It's syntax isn't that bad, but I think it gets a bit verbose for multiple validations-per-value. I built my own validation extender/binding-handler pair for Knockout that I use, and it doesn't have any issue with RequireJs.

It consists of an extender and a binding handler.

The binding handler

<input type="text" data-bind="validate: title" />

validate wraps the standard value binding, and sets the isModified sub-observable on the extended observable. This stops errors from showing before the element has been ineteracted with.

The extender

Like ko-validation I use an extender, but unlike ko-validation I use just one: isValid. It add's four sub-observables to the extended observable:

isValid() - boolean indicating the validity.

isModified() - boolean indicating whether the value has been touched. It is set to true by the validate binding handler

showError() - boolean indicating whether the error message should be shown. It is !isValid() && isModified().

errorMessage() - the error message to display.

It supports several syntaxes, ranging from "bare-minimum" to "totally customized."

Custom validation

If you pass a function to validate it will be used to test the validity of the observable. The function will recieve any value written, and the value will be invalid if the function returns false. If the custom function accesses any observables, it will establish a dependency and re-run when those observables change (just like a computed).

The extender can also take an array of validation objects, each of which will be used to determine validity. The errorMessage sub-observable will be set to the message of the first failing specification only.

That's it

From this, you should be able to create any kind of validation you need. Let me know what you think. The source is located on Github.

This code was developed at work, and is being open sourced because I have an awesome manager. Thanks Ken!