0
votes

I have a page with some knockout in it that I am trying to implement validation in. I have an input that I allow the user to change with a drop down like this:

<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 href="javascript:set_Term(12)">12 Months</a></li>
                <li><a href="javascript:set_Term(24)">24 Months</a></li>
                <li><a href="javascript:set_Term(36)">36 Months</a></li>
                <li><a href="javascript:set_Term(48)">48 Months</a></li>
                <li><a href="javascript:set_Term(60)">60 Months</a></li>
                <li><a href="javascript:set_Term(72)">72 Months</a></li>
                <li><a href="javascript:set_Term(84)">84 Months</a></li>
            </ul>
        </div>
    </div>
    <span data-bind='visible: Term.hasError, text: Term.validationMessage' class="help-block"></span>
</div>

And the JavaScript function:

function set_Term(months) {
    var termInput = document.getElementById("tbTerm");
    termInput.value = months;           
};

The value is tied to:

self.Term = ko.observable('').extend({ required: 'Term is required' });

The observable is updated when the value changes, but the error state remains the same and the input stays red and the feedback remains visible. Is there a way to force the input to realize that it's value has been changed and it should clear the error?

I've tried to give the element focus(), but that doesn't work.

The only thing that I have found is to give the containing div and the validation message ids and then do this in the JS function:

  $('#tbTermDiv').removeClass('has-error');
  $('#tbTermNote').addClass('hidden');

Which visually does the trick - the error message goes away and the text box loses the red, but if the user then empties the box again, the red comes back but the message stays hidden... so not the best solution.

I'd be happy with any kind of solution: knockout, jQuery, pure JS.

Edit: I have noticed that this does not update the observable, so when I change the input via the value property it does not update the observable.

1
What causes your validation to appear? What validation library are you using at the moment?Jason Spake
@JasonSpake I'm using the example found here: knockoutjs.com/documentation/extenders.htmlBarry Franklin
@JasonSpake I also have knockout.validation v2.0.3 by Eric Barnard installed, but I'm not sure if what I have set up uses it.Barry Franklin
I don't see anything wrong with what you have. I threw together a quick repro using your code and the "required" extender from knockout's samples. It appears to work correctly? jsfiddle.net/jlspake/8ob0gj6q Is it only after using one of the set_term functions that there's an issue?Jason Spake
Oh there's more going on here. Is that a bootstrap dropdown?Jason Spake

1 Answers

1
votes

The extender works the same way knockout in general works. It's only aware of changes that are done to observables on a view-model. Updating the value of a control on the UI using jquery won't update the underlying view-model so any dependent knockout code doesn't know to update.

You can change your set_term function to be a function on the view-model, and have it update the underlying observable instead of the control. Then use a data-bind to call the function instead of raw js.

  self.set_Term = function(months) {
      self.Term(months);
  };

...

  <li><a data-bind="click: function(){set_Term(84)}">84 Months</a></li>

Here's an updated example: https://jsfiddle.net/jlspake/8ob0gj6q/3/