Reputation: 41
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
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
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