Memphis
Memphis

Reputation: 271

Knockout - Checking checkboxes according to observableArray

So I have a list of schedules that I need to display for a user and show which schedules he or she is currently on and give them the possibility to jump on and off said schedules.

My viewmodel looks like this

self = this;
self.shifts = ko.observableArray();
self.selectedShifts = ko.observableArray();

//I populate self.shifts here with a WEB API call

//Run through each shift and check if current user is on it and set checked / not checked    value for checkbox
        ko.utils.arrayForEach(self.shifts(), function(shift) {

           //Clear array
            self.usersOnShift([]);

            //Populate array with all users on the shift
            self.usersOnShift = ko.observableArray(WEB API CALL HERE);

            var userInShift = ko.utils.arrayFirst(self.usersOnShift(), function(user) {
                if (selectedUserId == user.ID) {
                    return true;
                } 
            });

            if (userInShift) {

                self.selectedShifts.push(shift.ID);
            }
        });

ko.applyBindings(self);

My HTML looks like this

  <div class="simple_overlay" id="shiftOverlay">
        <div class="details">

            <div data-bind="foreach: shifts">

                <div><span class="staff-initials" data-bind="text:wardName">  </span><input type="checkbox" data-bind="value: ID, checked: $root.selectedShifts"/>  </div>
            </div>
            <div>
                <a href="#" data-bind="click: updateUserOnShifts">Connect</a>
                <a href="#" data-bind="click: closeShiftDialog">Close</a>
            </div>
        </div>
    </div>

I can see that the value of the checkboxes are set correctly to the ID of the corresponding shifts. However a shift that I know the user in question is on is not checked and I know that the selectedShifts observableArray contains the value.

Somehow the "checked: $root.selectedShifts" call / check is not working but I know that it contains the right value. What am I doing wrong?

Upvotes: 1

Views: 3119

Answers (2)

Michael Best
Michael Best

Reputation: 16688

The problem is that your value is an integer, but when bound to the checkbox element, it becomes a string. When the checked binding tries to find the value in the array, it doesn't find a match because it uses strict equality for comparison and (2 === "2") is false.

The simplest way to work around this problem is to convert your values to string when you add them to the array:

self.selectedShifts.push("" + shift.ID);

Of course this means that your model has to change, and that might not be a great solution. I came up with a custom binding, checkedInArray that replaces checked and supports any type of value. You can learn about it, see it in action, and use it like this:

<input type="checkbox" data-bind="checkedInArray: {value: ID, array: $root.selectedShifts }" />

In Knockout 2.3.0 (which is still in development) there will be a new binding, checkedValue, that will allow you use any type of value with the checked binding. Using that version, you could update your HTML to use checkedValue:

<input type="checkbox" data-bind="checkedValue: ID, checked: $root.selectedShifts"/>

Upvotes: 10

Paul Manzotti
Paul Manzotti

Reputation: 5147

Is shift.ID an observable property? If it is, then you need to add it to the array like this:

self.selectedShifts.push(shift.ID());

Otherwise you're just adding the whole observable to the array, and not the value.

Upvotes: 0

Related Questions