Knockout ValidateAble Extender

by straeger

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-debug.js"></script>
<span data-bind="text: a"></span>
<br/>
<input type="text" data-bind="textInput: a" />
<br/>
<span data-bind="text: a.hasvalidationMessages"></span>
<hr/>

<span data-bind="text: b"></span>
<br/>
<span data-bind="text: b.hasvalidationMessages"></span>

<hr/>
<span data-bind="text: c().aax"></span>
<br/>
<span data-bind="text: c().aax.hasvalidationMessages"></span>


<hr/>
<span data-bind="text: x"></span>
<br/>
<span data-bind="text: typeof x.hasvalidationMessages"></span>

JavaScript

ko.extenders.validateable = function(target, rules) {
  target.hasError = ko.observable(false);
  target.validationMessages = ko.observableArray();
  target.hasvalidationMessages = ko.computed(function() {
    return target.validationMessages().length > 0;
  });
  target.resetValidationMessages = function() {
    target.validationMessages([]);
  };
  target.combinedValidationMessages = ko.computed(function() {
    var ret = "";
    ko.utils.arrayForEach(target.validationMessages(), function(message) {
      ret += message;
    });
    return ret;
  });
  target.rules = ko.observableArray(rules);
  target.addValidationMessage = function(message) {
    if (!_.contains(target.validationMessages(), message)) {
      target.validationMessages.push(message);
    }
  };
  target.hasValidationRules = ko.computed(function() {
    return target.rules().length !== 0;
  });
  var _validate = function(newValue) {
    if (target.hasValidationRules()) {
      var rules = target.rules();
      rules.map(function(rule) {
        var validationResult = rule(newValue);
        target.hasError(!validationResult.isValid);
        target.validationMessages.push(validationResult.message);
      });
    }
  };
  target.validate = _validate;
  _validate(target());
  // attach to value change
  target.subscribe(_validate);
  return target;
};

var vm = {};
vm.a = ko.observable("Init");
vm.b = ko.computed(function() {
  return vm.a() + ' <---- a value';
})

vm.x = ko.observable("x");
vm.c = ko.computed(function() {
  return {
    aax: ko.observable("Init aax").extend({
      validateable: []
    })
  }
})

vm.a.extend({
  validateable: []
});
vm.b.extend({
  validateable: []
});

ko.applyBindings(vm);