Knockout-Validation lib – clean patterns

Knockout-Validation on GitHub

which also leverages the jQueryValidation lib

All Bootstrap v3 compatible

Coolest architectural nugget = applying validation rules to VM observables (not inside HTML <input> markup)

one clear reason why that is a better way -> when the VM field is bound to multiple UI points, you only define the rule once vs many

var myVM = function() {

    var self = {};

    // simple required
    self.orderId = ko.observable().extend({ required: true });

    // conditionally required
    self.orderId = ko.observable().extend({ required: { onlyIf: self.isDelivery } });

    // required with field name in error message - LUVIN HOW SIMPLE THIS IS!
    self.orderId = ko.observable().extend({ required: "Order#" });

    // conditionally required with fieldname
    self.orderId = ko.observable().extend({ required: { params: "Order#", onlyIf: self.isDelivery } });

    return self;
}();

see the wiki for all Native and User Contributed rules available OOB.
 
above field name in error message examples require the following global rule.message tweak…

overriding default error messages

** must execute BEFORE all observable.extend definitions on your VM **

ko.validation.rules["required"].message = "{0} required";

HTML sample – basic knockout data-bind’ing (in case you’re new : )

<input type="text" class="form-control" placeholder="Order Id" data-bind="value: orderId">

HTML sample – summary error block

<div data-bind="visible: validation.isAnyMessageShown()" class="bg-danger errorGroup">please enter required fields</div>

 

summary with errors listed

<ul data-bind="visible: validation.isAnyMessageShown(), foreach: validation" class="bg-danger errorGroup">
    <li data-bind="text: $data"></li>
</ul>

 

initialization

ko.validation.init({
    errorElementClass: "error", //apply this to the <input> elements, see css... Bootstrap provides .has-error but it must be applied to the <input>'s parent element which requires extra cruft for ko.validation to play along... i prefer this simple approach
    decorateInputElement: true, //in tandem with above
    insertMessages: false //i prefer errorElementClass bringing minimal attention to each field and then bundled error message summary elsewhere
});

clear error boxes when blanking out properties (e.g. after a save)

self.validation.showAllMessages(false);

gotta have a handy isValid right?

** must execute AFTER all observable.extend definitions on your VM **

self.validation = ko.validation.group(self);
self.isValid = function () {
    self.validation.showAllMessages();
    return self.validation().length === 0;
}
return self;

Usage

self.saveMe = function() {
  if (!self.isValid()) return;
  ...
}

CSS for comprehensiveness ( < word?)… completeness? arrrg what is the phrase that pays here (alternative languages welcome : )

.error {
    border-color: #a94442;
}

.errorGroup {
    margin-top: 10px;
    padding: 5px;
    border-radius: 5px;
    text-align: initial;
}
.errorGroup li {
    margin-left: 15px;
}

Knockout, Validation, Bootstrap skinned File Input

 

Visual example:


 
Highlights:

  • Skinning the native html <input type=”file”> by setting it’s opacity=0 and positioning above a bootstrap looking button… this way when you click the pretty button you’re really clicking on the invisible native button which launches the file open dialog.
  • Bootstrap input-group aesthetically bundles the visual elements – file button, filename box, valiation message and clear button
  • Knockout Custom Binding on the file input change event to save into VM observable
  • Knockout-Validation lib to require selected file to be an image type – nice thing here is keeping that logic in the js ViewModel vs dirtying the html with it.
     
     

Live Demo:

See the Pen Knockdown, Validated, Bootstrap skinned File Input by Brent Anderson (@Beej2020) on CodePen.