1

I have an array of objects with an observable property that is being bound to a group of radio buttons. The observable property can only have the following values ['Primary', 'Secondary', 'Occasional', 'none']

Here's the HTML.

<!--ko foreach: allDriversForPolicy-->
<div class="col-md-2">
    <a href="#" class="thumbnail">
        <div class="">
            <label><input type="radio" value="Primary" data-bind="checked: vehicleDriverType, attr: {name: id}"/>Primary</label>
            <label><input type="radio" value="Secondary" data-bind="checked: vehicleDriverType, attr: {name: id}" />Secondary</label>
            <label><input type="radio" value="Ocasional" data-bind="checked: vehicleDriverType, attr: {name: id}" />Ocasional</label>
            <label><input type="radio" value="" data-bind="checked: vehicleDriverType, attr: {name: id}" />None</label>
        </div>
    </a>
</div>
<!--/ko-->

And here is the JavaScript to get it running.

var SimpleListModel = function() {
    this.allDriversForPolicy = ko.observableArray([
    {'id': 'abe', 'vehicleDriverType': 'Primary'},
    {'id': 'bob', 'vehicleDriverType': 'Secondary'},
    {'id': 'charlie', 'vehicleDriverType': ''}
    ]);
};

ko.applyBindings(new SimpleListModel());

jsfiddle is here. The wrinkle I'm running into is an added requirement that out of all the objects there can only be one primary so I'd like the behaviour to be if Primary is selected then go through the array and switch any objects with the observable property set to 'Primary' to 'Secondary'.

How can I do this?

4
  • 1
    Please remove any code not relevant to the question, and add enough code to reproduce your scenario. Commented Feb 22, 2016 at 6:44
  • All right I've trimmed it down. That'll reproduce the basics of what I have now. Commented Feb 22, 2016 at 6:58
  • Could you add the JS needed to create a full repro? For an example, see this recent answer I posted, for guidance see minimal reproducible example. Commented Feb 22, 2016 at 7:11
  • I've added code for a simple reproduction and a link to the jsfiddle I created it in. Commented Feb 22, 2016 at 8:20

1 Answer 1

1

Note: you have a rather weird bit of markup with the a tag wrapping all the other code. I've removed that bit in my example below.

The requirement you have will be very difficult to implement in a MVVM / Knockout style, because you don't have a backing observable for the selected radio button values. Once you change that, you can choose multiple ways to implement your requirement, including:

  • Creating writeable computeds for the backing observables, where the write bit updates the sibling observables;
  • Creating subscriptions to all individual backing observables.

Here's an example of the latter option:

var SimpleListModel = function() {
  var self = this;
  
  this.allDriversForPolicy = ko.observableArray([{
    'id': 'abe',
    'vehicleDriverType': ko.observable('Primary')
  }, {
    'id': 'bob',
    'vehicleDriverType': ko.observable('Secondary')
  }, {
    'id': 'charlie',
    'vehicleDriverType': ko.observable('')
  }]);
  
  self.allDriversForPolicy().forEach(function(i) {
    i.vehicleDriverType.subscribe(function(newVal) {
      if (newVal !== 'Primary') return;
      self.allDriversForPolicy().forEach(function(p) {
        if (p !== i && p.vehicleDriverType() === 'Primary') {
          p.vehicleDriverType('');
        }
      });
    });
  });
};

ko.applyBindings(new SimpleListModel());
pre { background: white; padding: 10px; color: #333; font: 11px consolas; border: 1px solid #ddd; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<!--ko foreach: allDriversForPolicy-->
<div class="col-md-2">
  <div class="">
    <label>
      <input type="radio" value="Primary" data-bind="checked: vehicleDriverType, attr: {name: id}" />Primary</label>
    <label>
      <input type="radio" value="Secondary" data-bind="checked: vehicleDriverType, attr: {name: id}" />Secondary</label>
    <label>
      <input type="radio" value="Ocasional" data-bind="checked: vehicleDriverType, attr: {name: id}" />Ocasional</label>
    <label>
      <input type="radio" value="" data-bind="checked: vehicleDriverType, attr: {name: id}" />None</label>
  </div>
</div>
<!--/ko-->

<hr>Debug info: <pre data-bind="text: ko.toJSON($root, null, 2)"></pre>

PS. I suggest creating a seperate constructor function for the items in that array, which will make for a lot clearer code (the nested forEaches will become a lot better if you do).

Sign up to request clarification or add additional context in comments.

1 Comment

Ah sorry about that. There's an image tag missing in my example(it wasn't necessary for the problem). My plan is to make the whole thing a thumbnail and have the select list appear when you hover over it. Clicking on something that isn't the radio button list will bring up a file upload dialog to change the image. That's the plan anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.