https://stackoverflow.com/questions/44265973/element-not-updating-error-state-when-value-changed-via-javascript

by jlspake

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<div class="col-md-6 form-group has-feedback" data-bind="css: { 'has-error': Term.hasError }">
    <label for="ddlTerm" class="col-form-label" style="padding: 0;">Term</label>
    <div class="input-group input-group-sm">
        <input type="text" data-bind="textInput: Term" class="form-control input-sm" id="tbTerm" />
        <div class="input-group-btn">
            <button type="button" class="btn btn-warning dropdown-toggle" data-toggle="dropdown">Select <span class="caret"></span></button>
            <ul class="dropdown-menu pull-right">
                <li><a data-bind="click: function(){set_Term(12)}">12 Months</a></li>
                <li><a data-bind="click: function(){set_Term(24)}">24 Months</a></li>
                <li><a data-bind="click: function(){set_Term(36)}">36 Months</a></li>
                <li><a data-bind="click: function(){set_Term(48)}">48 Months</a></li>
                <li><a data-bind="click: function(){set_Term(60)}">60 Months</a></li>
                <li><a data-bind="click: function(){set_Term(72)}">72 Months</a></li>
                <li><a data-bind="click: function(){set_Term(84)}">84 Months</a></li>
            </ul>
        </div>
    </div>
    <span data-bind='visible: Term.hasError, text: Term.validationMessage' class="help-block"></span>
</div>

JavaScript

var viewModel = function(){
	var self = this;
  
  self.Term = ko.observable('').extend({ required: 'Term is required' });
  
  self.set_Term = function(months) {
      self.Term(months);
  };
}

ko.extenders.required = function(target, overrideMessage) {
    //add some sub-observables to our observable
    target.hasError = ko.observable();
    target.validationMessage = ko.observable();
 
    //define a function to do validation
    function validate(newValue) {
       target.hasError(newValue ? false : true);
       target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
    }
 
    //initial validation
    validate(target());
 
    //validate whenever the value changes
    target.subscribe(validate);
 
    //return the original observable
    return target;
};
 

ko.applyBindings(new viewModel());