2
votes

I'm having an issue with a checkbox input in my Knockout code that updates the viewmodel correctly, but does not update until the div surrounding it disappears and re-appears. We're using Knockout 3.2.0, currently.

Here's a subset of the relevant HTML:

<!-- ko foreach: objects -->
<!-- ko if: isType(typeCodes.INPUT) -->
<!-- ko if: selected -->
<div data-bind="fadeVisible: $root.isState(uiState.IDLE)" id="typeInputContainer">
    <!-- ko foreach: $root.types -->
        <div class="checkbox patientType">
            <input type="checkbox" data-bind="attr: {id: 'checkPt' + $data.patientTypeValue() }, checked: $data.visible" />
        </div>
    <!-- /ko -->
</div>
<!-- /ko -->
<!-- /ko -->
<!-- /ko -->

And here's a subset of the viewmodel:

function PatientType(name, value, color) {
    var self = this;
    self.typeName = ko.observable(name);
    self.visible = ko.observable(true);
    //Disposal
    self.isDisposed = false;
    self.dispose = function() {
        self.color().dispose();
        self.isDisposed = true;
    };
}

Apologies for the drastic reduction, but the surrounding code in each case is highly verbose and not particularly related to the problem.

When I step through the code at the highest level on the call stack, a JQuery function for event handling (below), clicking the checkbox will cause this to be called around five or six times, and at each point after the first, the checkbox has changed to correctly reflect the updated viewmodel.

However, after that "thread" of execution has finished, the checkbox immediately reverts to its previous state. Only when the div is removed (by deselecting the object referenced at the top line of the HTML) and re-added (by re-selecting it) does the checkbox correctly reflect the viewmodel.

Initially, I thought the UI change was halted by a number of subscriptions assigned to various changes caused by this update in the viewmodel, but I found that the problem persisted when these subscriptions were temporarily removed. There are other checkboxes within the application that function as intended and are written in much the same way.

The JQuery 2.1.1 code mentioned above:

eventHandle = elemData.handle = function( e ) {
    // Discard the second event of a jQuery.event.trigger() and
    // when an event is called after a page has unloaded
    return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
        jQuery.event.dispatch.apply( elem, arguments ) : undefined;
    };

And the definition of the fadeVisible binding, in case it's relevant:

ko.bindingHandlers.fadeVisible = {
    init: function (element, valueAccessor) {
        // Initially set the element to be instantly visible/hidden depending on the value
        var value = valueAccessor();
        $(element).toggle(ko.unwrap(value)); // Use "unwrapObservable" so we can handle values that may or may not be observable
    },
    update: function (element, valueAccessor) {
        // Whenever the value subsequently changes, slowly fade the element in or out
        var value = valueAccessor();
        ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut();
    }
};

Any suggestions on what could be causing this would be much appreciated.

1
Where is the fadeVisible div closed? What is controlling the select/deselect. My fiddle. - Origineil
What version of Knockout? - Michael Best
Is it possible to provide a jsfiddle that demonstrates the problem? - Wayne Ellery
@Originiell An object is de/selected depending on whether or not its on-screen representation has been clicked on - the application also uses JsPlumb, the code for which I didn't include as I didn't think it would be relevant. As for the div closure, I forgot to add it - that's been corrected now. Michael, we're using Knockout 3.2.0, thanks for asking. I've updated the question with this information. Unfortunately, the project uses so many libraries that to reduce it to something that could make sense in JsFiddle wouldn't replicate the problem. - Dan McElroy

1 Answers

0
votes

Don't know this is relevant, but I experienced an issue where radio button unselected after rebinding. Fixed once I replaced data-bind="if: with data-bind="visible: