Guillaume
Guillaume

Reputation: 180

Dynamic Radio button bind checked property is dynamic

first of all I'm new to knockout/javascript and I'm currently working on a "Not done" project which I'm creating a "dynamic options" the problems is that my ViewModel is binded to my ItemModel( which contains 5 property HS01 - HS02 - HS03 - HS04 - HS05) which need to the binded when OptionsBox is selected. Checked: $parent.(dynamic property) seem to not work.

Here's code sample.

HTML

<input data-bind="value: HS01" />
                            <table class="table table-condensed">
                                <tbody data-bind="foreach: HealthAndSafety">
                                <tr>
                                    <td class="col-xs-9">
                                        <span data-bind="html: contenu"></span>
                                        <!-- ko if: $data.id == 'HS01' -->
                                        <br/>
                                        <ul style="list-style-type: disc">
                                            <!-- ko foreach: $root.HealthAndSafetyChild -->
                                            <li data-bind="text: $data.contenuChild"></li>
                                            <!-- /ko -->
                                        </ul>
                                        <!-- /ko -->
                                    </td>
                                    <!--<div style="border: 3px red dashed;">-->
                                    <td class="col-xs-2">
                                        <input type="radio"  data-bind="attr:{value:id,name:group,checked: checkedProperty} , checkedValue: 0"/>
                                        <input type="radio"  data-bind="attr:{value:id,name:group,checked: checkedProperty} , checkedValue: 1"/>
                                    </td>
                                </tr>
                                </tbody>
                            </table>

JavaScript (viewmodel) here is that each UL has multiple Li etc... then they are only 1 yes/no radio button that are binding to parent viewmodel

 m.HealthAndSafety = ko.observableArray([
                 { id: 'HS01', group: 'HS01Group', checkedProperty: '$parent.HS01', contenu: f.lang('HealthSafety01') },
                 { id: 'HS02', group: 'HS02Group', checkedProperty: '$parent.HS02', contenu: f.lang('HealthSafety02') },
                 { id: 'HS03', group: 'HS03Group', checkedProperty: '$parent.HS03', contenu: f.lang('HealthSafety03') },
                 { id: 'HS04', group: 'HS04Group', checkedProperty: '$parent.HS04', contenu: f.lang('HealthSafety04') },
                 { id: 'HS05', group: 'HS05Group', checkedProperty: '$parent.HS05', contenu: f.lang('HealthSafety05') }]);
            m.HealthAndSafetyChild = ko.observableArray([{ idChild: 'HS01_1', contenuChild: f.lang('HealthSafety01_1') }, { idChild: 'HS01_2', contenuChild: f.lang('HealthSafety01_2') }, { idChild: 'HS01_3', contenuChild: f.lang('HealthSafety01_3') }, { idChild: 'HS01_4', contenuChild: f.lang('HealthSafety01_4') }, { idChild: 'HS01_5', contenuChild: f.lang('HealthSafety01_5') }, { idChild: 'HS01_6', contenuChild: f.lang('HealthSafety01_6') }]);

When I post my model to update database Property HS01 etc.. are null and are not binded. I have tested multiple case but I don't get how to bind my ObservableArray (CheckedProperty) to the checked Property.

I have also tried

<input type="radio"  data-bind="attr:{value:id,name:group} checked: (checkedProperty / #data.checkedProperty) , checkedValue: 0"/>

All the example I found on Stackoverflow are all binded to only 1 property

Thanks!

Edit1 http://jsfiddle.net/grosjambon/azz3tpfy/7/

Edit2 Found a cleaner way to fix my problems still not fully optimal but better to my other one with multiple If condition in the html. while implementing Roy answer

HTML

 <div style="border: 3px red dashed;">
                                                <label class="radio-inline">
                                                    <input type="radio" data-bind="attr:{name:id}, checked: checkedProperty, checkedValue: '1',event: {change : $root.onInputChangeUpdateVMHSProperty }" />
                                                    Yes
                                                </label>
                                                <label class="radio-inline">
                                                    <input type="radio" data-bind="attr:{name:id}, checked: checkedProperty, checkedValue: '0' ,event: {change : $root.onInputChangeUpdateVMHSProperty }" />
                                                    No
                                                </label>
                                            </div>         

JavaScript

m.onInputChangeUpdateVMHSProperty = function (item) {
                switch (item.id) {
                    case "HS01":
                        m.HS01(item.checkedProperty());
                        break;
                    case "HS02":
                        m.HS02(item.checkedProperty());
                        break;
                    case "HS03":
                        m.HS03(item.checkedProperty());
                        break;
                    case "HS04":
                        m.HS04(item.checkedProperty());
                        break;
                    case "HS05":
                        m.HS05(item.checkedProperty());
                        break;                       
                }                  
            };

Upvotes: 1

Views: 1218

Answers (1)

Roy J
Roy J

Reputation: 43881

Main issues:

  1. Don't use the checked attribute, use the checked binding
  2. Instead of the name of an observable, checkedProperty should be an observable itself

So the elements of your array will look like this:

{
  id: 'HS01',
  group: 'HS01Group',
  group2: 'HS01Group2',
  checkedProperty: ko.observable(),
  contenu: 'test1'
}

Your row of inputs would be:

<div data-bind="foreach: HealthAndSafety">
  <span data-bind="text: $index"></span>
  <input data-bind="value: checkedProperty" />
</div>

Your radio buttons would look like:

<input type="radio" data-bind="attr:{name:id}, checked: checkedProperty, checkedValue: '0'" />

function SeatReservation(name, initialMeal) {
  var self = this;
  self.name = name;
  self.meal = ko.observable(initialMeal);
}


// Here's my data model
var ViewModel = function() {
  var self = this;

  self.HealthAndSafety = ko.observableArray([{
    id: 'HS01',
    group: 'HS01Group',
    group2: 'HS01Group2',
    checkedProperty: ko.observable(),
    contenu: 'test1'
  }, {
    id: 'HS02',
    group: 'HS02Group',
    group2: 'HS02Group2',
    checkedProperty: ko.observable(),
    contenu: 'test2'
  }, {
    id: 'HS03',
    group: 'HS03Group',
    group2: 'HS03Group2',
    checkedProperty: ko.observable(),
    contenu: 'test3'
  }, {
    id: 'HS04',
    group: 'HS04Group',
    group2: 'HS04Group2',
    checkedProperty: ko.observable(),
    contenu: 'test4'
  }, {
    id: 'HS05',
    group: 'HS05Group',
    group2: 'HS05Group2',
    checkedProperty: ko.observable(),
    contenu: 'test5'
  }]);
};

ko.applyBindings(new ViewModel()); // This makes Knockout get to work
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div>
  <h1>
 Just testing if the property get binded when u click a radioButton 
 </h1>
  <h1>
  Example that works now
  </h1>
  <div data-bind="foreach: HealthAndSafety">
    <span data-bind="text: $index"></span>
    <input data-bind="value: checkedProperty" />
  </div>
  <table>
    <tbody data-bind="foreach: HealthAndSafety">
      <tr>
        <td class="col-xs-2">
          <input type="radio" data-bind="attr:{name:id}, checked: checkedProperty, checkedValue: '0'" />
          <input type="radio" data-bind="attr:{name:id}, checked: checkedProperty, checkedValue: '1'" />
        </td>

      </tr>
    </tbody>
  </table>
</div>

Upvotes: 2

Related Questions