1

I'm having issues with the checked binding in a checkbox list.

JS

function vm() {
    var self = this;

    self.categories = [
        {id: 1, name: "Category 1"},  
        {id: 2, name: "Category 2"},  
        {id: 3, name: "Category 3"}
    ];

    // Assume this item came from server side, 
    // that's why i'm using the mapping plugin here.
    var rawItem = { links: [1] };
    self.item = ko.mapping.fromJS(rawItem);
}

ko.applyBindings(new vm());

HTML

<div data-bind="foreach: categories">
    <div>
        <label>
            <span data-bind="text: name"></span>
            <input class="checkbox" type="checkbox" data-bind="checked: $root.item.links, attr: {value: id}">
         </label>
    </div>
</div>

<div data-bind="text: ko.toJSON(item.links)"></div>

JSFiddle

As you can see in the fiddle, first issue is that the "id" property from the self.category items is somehow casted to a string, and that is causing the comparison fail. Anyway, casting the item links to string don't work as expected too.

In short, goal is: check fields on page load according to values from the categories array.

Since i'm reproducing this from a more complex scenario, I've added the mapping plugin to put in any possible factor.

brazorf
  • 1,943
  • 2
  • 32
  • 52
  • It's not very clear from what you have wrote what it is you're trying to achieve, it's all there, it just doesn't make much sense, could you explain step by step? – Callum Linington May 21 '14 at 22:34
  • If you run the fiddle, you'll see that checkboxes don't assume the expected checked status (category 1 should be flagged). – brazorf May 21 '14 at 23:55

2 Answers2

2

Your Json object has invalid key, JSON only allows key names to be strings. Thats why you see id as string.

Html

<div data-bind="foreach: categories">
    <div>
        <label>
            <span data-bind="text: name"></span>
            <input class="checkbox" type="checkbox" data-bind="value: id, checked: $root.item">
         </label>
    </div>
</div>

<div data-bind="text: ko.toJSON(item)"></div>

JavaScript

function vm() {
    var self = this;

    self.categories = [
        {id: "1", name: "Category 1"},  
        {id: "2", name: "Category 2"},  
        {id: "3", name: "Category 3"}
    ];

    // Assume this item came from server side, 
    var rawItem = { links: ["1"] };
    self.item = ko.observableArray(rawItem.links);
}

ko.applyBindings(new vm());

Here's jsfiddle

Community
  • 1
  • 1
GSerjo
  • 4,725
  • 1
  • 36
  • 55
  • Thank you, this sounds totally new to me. And this is not clear aswell... i mean, i can not use an array of integer values? – brazorf May 21 '14 at 23:52
  • You can, but have to convert to string, here's similar [sample](http://jsfiddle.net/krudy/NBLeg/) – GSerjo May 22 '14 at 06:18
  • I'm not sure anymore that the reason is what you pointed out as "JSON only allows key names to be strings", since i'm not working with keys, i'm working with properties value. See my answer for details and let me know if i didn't got you right. – brazorf May 22 '14 at 11:01
  • Yes, order is important. About compare int and string, `===` is more correct and 1!="1" if `===` is used. As you see integer is converted to string automatically, but if `links`doen't contain a string the selction is not working – GSerjo May 22 '14 at 11:46
0

There are two problems there.

1) Cast to string

<input class="checkbox" type="checkbox" data-bind="checked: $root.item.links, value: id">

The "value" binding is somehow casted to string by KO itself before the comparison. Infact, if i try to use integer values for the category ids, and string values for the item links, the checked bingind is working. You can see this here

It seems like that id property, used to check if category.id == item.links[i], is casted turning the comparison into something like "1" == 1 if item.links = [1, 2, 3], or into "1" == "1" if item.links = ["1", "2", "3"], even if each category.id is an integer.

2) Bindings order

If the checked binding is declared before the value binding, the check operation occurrs after the first value change. See here: the only difference with the working code is that value comes before checked. Try to load that fiddle and check option 3.

So, in order to fix these,

  1. item.links values must be strings
  2. the correct bindings order is value:id, checked: $root.item.links
brazorf
  • 1,943
  • 2
  • 32
  • 52