user2071704
user2071704

Reputation: 41

Radio button not working within nested ng-repeats

I have a web page with check boxes & radio buttons within nested ng-repeats. When I am clicking the check boxes the underlying view model is getting updated properly, but when I click on the radio buttons, the view model is not getting updated properly. Within a group, when I select an option the selected model property gets updated to true but the other one doesn't change to false.

e.g. when I click on the radio buttons against chicken one by one, all of them becomes true. When I select any one, I want the other ones to become false

My view model is given below.

$scope.itemGroups = [{
        "name": 'Non Veg',
            "items": [{
            "selected": false,
                "name": 'Chicken',
                "Portions": [{
                "selected": false,
                    "name": '1 Cup'
            }, {
                "selected": false,
                    "name": '2 Cups'
            }, {
                "selected": false,
                    "name": '3 cups'
            }]
        }, {
            "selected": true,
                "name": 'Egg',
                "Portions": [{
                "selected": false,
                    "name": '1 Cup'
            }, {
                "selected": false,
                    "name": '2 Cups'
            }, {
                "selected": false,
                    "name": '3 cups'
            }]
        }]
    }, {
        "name": 'Veggie',
            "items": [{
            "selected": false,
                "name": 'Potato',
                "Portions": [{
                "selected": false,
                    "name": '1 Cup'
            }, {
                "selected": false,
                    "name": '2 Cups'
            }, {
                "selected": false,
                    "name": '3 cups'
            }]
        }, {
            "selected": false,
                "name": 'Tomato',
                "Portions": [{
                "selected": false,
                    "name": '1 Cup'
            }, {
                "selected": false,
                    "name": '2 Cups'
            }, {
                "selected": false,
                    "name": '3 cups'
            }]
        }]
    }];

The way I bind to the html:

<div ng-repeat="itemGrp in itemGroups">
             <h1>{{itemGrp.name}}</h1>

            <div ng-repeat="item in itemGrp.items">
                <input type="checkbox" ng-model="item.selected" />{{item.name}}
                <label ng-repeat="portion in item.Portions">{{portion.name}}
                    <input type="radio" name="radio_{{itemGrp.name}}" ng-model="portion.selected" ng-value="true" />
                </label>
            </div>
        </div>

Fiddle: http://jsfiddle.net/awqv0rb0/16/

Can you please guide me on what can be the issue here? Is there a better way of achieving what I am trying to do here? I need to loop through the JSON and get the values of the selected items.

Upvotes: 0

Views: 1027

Answers (2)

brae
brae

Reputation: 1122

The code you have posted here doesn't quite match the fiddle you provided, but your issue is the result of giving each radio button it's own name, and therefore, it's own group. This allows all radio buttons to essentially function as check boxes and all be set to true instead of the desired behavior of allowing only one.

Instead, you should give all radio buttons under that item the same group name, like:

name="{{item.name}}" 

Your nested ng-repeats should look something like this when you're done:

<div ng-repeat="item in itemGrp.items">
  <input type="checkbox" ng-model="item.selected" />{{item.name}}
  <label ng-repeat="portion in item.Portions">{{portion.name}}
    <input type="radio" name="{{item.name}}" ng-model="portion.selected" ng-value="true" />
  </label>
</div>

Updated per your Comment

To update the selected:true value of each of your portions when you change one, you'll need a little bit more code. This is a little messy, so it may not be the best solution--but I was able to get it to work.

In addition to the ng-value="true" you should also add an ng-change="toggleRadio(itemGrp,item,portion)"to your radio buttons. In your js, you should add the following function:

 $scope.toggleRadio = function(itemGrp, item, obj) {
      var indexOfItemGrp = $scope.itemGroups.indexOf(itemGrp);
      var indexOfItem = $scope.itemGroups[indexOfItemGrp].items.indexOf(item);
      var indexOfPortion = $scope.itemGroups[indexOfItemGrp].items[indexOfItem].Portions.indexOf(obj);
        angular.forEach($scope.itemGroups[indexOfItemGrp].items[indexOfItem].Portions, function(value,key)     {
            if(indexOfPortion != key) {
                value.selected = false;
            }
        });
    };

Basically, this code will iterate through all of the portion options inside the item inside the itemGroup and update their value to false unless they were the selected option.

You can see a working example in a fork of your original fiddle that I created: here.


One More Update

Have a look at this question: AngularJS Binding Radio Buttons To Booleans Across Multiple Objects. If you can change the model of your json object, this might be a viable solution. If you can't change the model, manually updating the other values is your cleanest option.

Upvotes: 0

Dinesh Chitlangia
Dinesh Chitlangia

Reputation: 590

This is a trivial issue. I too, faced it an earlier stages.

If you are looping over a group of items and each item has a set of radio buttons, then all the radio buttons for a given item must have the 'name' attribute value as the item name.

Ex. If the item name is 'Chicken', all it's radio buttons labelled as '1 Cup', '2 Cups', '3 Cups' should have their name='{{item.name}}' i.e. 'Chicken'.

Change Point in your Code:

<input type="radio" name="{{item.name}}" ng-model="portion.selected" ng-value="true" />

Here is the JSFiddle demo

Upvotes: 0

Related Questions