Reputation: 1
My application has a select element that is data bound to an observableArray for its options and to an observable for its value. It also uses the optionsCaption binding. The problem is that the select element gets out of sync with the value observable. That is, the observable has one value, but the selectedIndex of the HTML select element is a different option. So what the user sees does not match the view model.
Here is the HTML:
<select data-bind="options:neighborhoods,optionsText:'name',optionsValue:'id',value:neighborhoodId,optionsCaption:'All'"></select>
And here is the relevant code from the view model:
this.neighborhoods = ko.observableArray();
this.neighborhoodId = ko.observable();
The neighborhoods array is populated from a REST API during initialization. When initialization is complete, everythings is working as expected. The HTML select has options corresponding to the objects in the neighborhoods obervableArray plus an option with no value whose text is "All". The neighborhoodId observable value is undefined and the selectedIndex value of the HTML select element is 0 (so the user sees "All"). The Chrome inspector shows this HTML:
<select data-bind="options:neighborhoods,optionsText:'name',optionsValue:'id',value:neighborhoodId,optionsCaption:'All'">
<option value="">All</option>
<option value="8">Back Bay</option>
<option value="12">
...
But after the user selects the "Back Bay" option, sumbmits the form, and then clicks the reset button to click the form, the neighborhoodId observable does not match what the user sees on the page. The click handler for the "Reset" button sets the value of the neighborhoodId observable to undefined. As expected, the user sees "All", and the selectedIndex property of the HTML select element is 0. But the value of the neighborhoodId observable is 12. Somehow it changes after the button handler sets it to undefined, without the DOM changing to reflect the new value.
This is happening in a moderately complex single page application. I have not been able to create a simple example that recreates the problem. So my question is, what techniques do you use to debug a situation in which the view model and the DOM get out of sync in a Knockout application?
Upvotes: 0
Views: 64
Reputation: 1
The problem was that I was using the same observable for the value of two different select elements. The UI has two different behaviors for the select, based on whether or not it is a required field. So I had this HTML:
<div class="col-8 pl-1" data-bind="visible:isRequired">
<select class="form-control" data-bind="value:neighborhoodId">
<option value="" disabled selected>required</option>
<!-- ko foreach:neighborhoods -->
<option data-bind="text:name,value:id"></option>
<!-- /ko -->
</select>
</div>
<div class="col-8 pl-1" data-bind="visible:!isRequired">
<select class="form-control" data-bind="options:neighborhoods,optionsText:'name',optionsValue:'id',value:neighborhoodId,optionsCaption:'All'"></select>
</div>
Only one of the select elements was visible at any time. But both data bindings were active, and fought with each other over the value of the observable. Changing "visible" to "if" in the data-bind attributes removed the inactive select element from the DOM and eliminated the problem.
Upvotes: 0