How to render an array as a list of radio buttons?
Asked Answered
S

4

10

I would like to loop through an array that I define in my Javascript and render a list of radio buttons. My code which isn't working currently, and it is as follows (also on jsfiddle):

<div data-bind="foreach: options" >
    <div>
        <input type="radio" name="optionsGroup" data-bind="checked: selected" />
        <span data-bind="text: label"></span>
     </div>    
</div>
var optionsList = [
    {"value": "a","label": "apple"},
    {"value": "b","label": "banana"},
    {"value": "c","label": "carrot"}
];
function viewModel() {
    var self = this;
    self.options = optionsList;
    self.selected = ko.observable("a");
    self.selected.subscribe(function(newValue) {
        alert("new value is " + newValue);
    });
}
ko.applyBindings(new viewModel());

If my array is part of the html then it works fine, see this (or jsfiddle):

<div>
    <input type="radio" name="optionsGroup" value="a" data-bind="checked: selected"     />Apple
</div>
<div>
    <input type="radio" name="optionsGroup" value="b" data-bind="checked: selected" />Banana
</div>
<div>
     <input type="radio" name="optionsGroup" value="c" data-bind="checked: selected" />Carrot
</div>
<div data-bind="text: selected">
</div>
function viewModel() {
    var self = this;
    self.selected = ko.observable("a");
    self.selected.subscribe(function(newValue) {
        alert("new value is " + newValue);
    });
}    
ko.applyBindings(new viewModel());

I got this to work by generating the all of the html within my javascript and have this working using checkboxes, but am stumped generating a group of radiobuttons using the foreach iterator.

Has anyone gotten an example like my first one to work?

Superannuated answered 19/1, 2012 at 3:4 Comment(2)
Surely you can come up with a more informative title.Haggerty
Worth noting you don't need var self = this in your viewModel. Delete that line and change all selfs to this. Scope's fine without.Grueling
C
17

Here's one way to do this. Note that the attr binding should come before the checked binding.

var optionsList = [
    {"value": "a", "label": "apple"},
    {"value": "b", "label": "banana"},
    {"value": "c", "label": "carrot"}
];

function viewModel() {
    this.options = optionsList;
    this.selected = ko.observable("a");
}

ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<h3>Fruits</h3>
<div data-bind="foreach: options" >
  <label>
    <input type="radio"
           name="optionsGroup" 
           data-bind="attr: {value: value}, checked: $root.selected" />
    <span data-bind="text: label"></span>
  </label>    
</div>

<h3>Selected value:</h3>
<pre data-bind="text: ko.toJSON($root.selected)"></pre>
Culberson answered 19/1, 2012 at 3:12 Comment(3)
My issue was the attr binding not coming before checked. Makes sense but not apparent right away.Sandglass
Fiddle of above answer in context (just for kicks).Grueling
In recents Knockout versions, $root has become $parentRissa
C
2

Your code is giving this error:

Message: ReferenceError: selected is not defined;

Bindings value: checked: selected

You defined selected on the view model level, but you are referencing it inside foreach so Knockout.js is looking for it on the options level.

Change:

<div><input type="radio" name="optionsGroup" data-bind="checked: selected" />

to:

<div><input type="radio" name="optionsGroup" data-bind="checked: $root.selected" />

$root.selected will look for the selected property on the view model level.

HERE is the modified code.

For more information about pseudo-variables (like $root) see 3. Access to parent binding contexts.

Conde answered 19/1, 2012 at 3:12 Comment(0)
M
1

To be able to have the entire object it's better to use checkedValue instead of attr: {value} like that :

Fruits
<div data-bind="foreach: options" >
    <div><input type="radio" name="optionsGroup" data-bind="checkedValue: $data, checked: $root.selected" />
    <span data-bind="text: label"></span></div>    
</div>
Mannequin answered 2/10, 2014 at 8:9 Comment(0)
D
0

You code is works. Just include knockout.js in your jsfiddle and set document "onDomready".

Daffodil answered 19/1, 2014 at 16:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.