Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Wrong behaviour of radio input inside ng-repeat with double values #16690

Closed
2 tasks
emaborsa opened this issue Sep 11, 2018 · 6 comments
Closed
2 tasks

Wrong behaviour of radio input inside ng-repeat with double values #16690

emaborsa opened this issue Sep 11, 2018 · 6 comments

Comments

@emaborsa
Copy link

emaborsa commented Sep 11, 2018

I'm submitting a ...

  • [ x] bug report
  • feature request
  • other

Current behavior:
I created a ng-repeat with a radio input inside. It bevavies strange when the ng-model of the radio is a nested object (ie. ng-model="data.fieldName"). Otherwise (ng-model="fieldName") it works fine.

Expected / new behavior:
As a radio usually behavies

Minimal reproduction of the problem with instructions:
Here the plunker.
The third radio works fine since it has no dupes. The first one has dupes but the ng-model is local and also works fine. The second one has dupes, is global and does not really works fine: Try to select 'Tetst2' and then select one of the 'Test' .

AngularJS version:
1.2.9 and 1.7.2

Browser:
Tested on Chrome, IE11, Edge. Same problem on all browsers

Anything else:
Here again the code:

<table ng-app="myApp" ng-controller="myCtrl">
  <tr>
    <td class="ms-cellstyle ms-vb2 hgv_data" ng-repeat="i in data">
      <input type="radio" ng-model="thisWorks" name="Title" ng-value="i.Title">
      <span>{{i.Title}}</span>
    </td>
  </tr>
  <tr>
    <td class="ms-cellstyle ms-vb2 hgv_data" ng-repeat="i in data">
      <input type="radio" ng-model="data.thisDoesNotWork" name="Title" ng-value="i.Title">
      <span>{{i.Title}}</span>
    </td>
  </tr>
  <tr>
    <td class="ms-cellstyle ms-vb2 hgv_data" ng-repeat="i in data">
      <input type="radio" ng-model="data.selectedAnotherValue" name="AnotherValue" ng-value="i.AnotherValue">
      <span>{{i.AnotherValue}}</span>
    </td>
  </tr>
</table>

`var myApp = angular.module('myApp', []);

myApp.controller('myCtrl', ['$scope', function ($scope) {
  $scope.data = [{
    ID: 1,
    Title: 'Test',
    AnotherValue: 'hello'
  }, {
    ID: 2,
    Title: 'Test2',
    AnotherValue: 'its'
  }, {
    ID: 3,
    Title: 'Test',
    AnotherValue: 'me'
  }];
}])`

@gkalpak
Copy link
Member

gkalpak commented Sep 11, 2018

This happens because you use the same name for all radio buttons in a group. This is what you need to do in traditional (non-AngularJS) apps, but AngularJS needs each radio to have a different name (they are grouped by their ngModel value instead).

See #15009 for more info.

@emaborsa
Copy link
Author

Thx for your answer, I read the other issue.
I updated the plunker added the ng-name instead the name attribute.
Could you tell me if the fourth example has the right behaviour? IMHO don't think so, but don't know how to fix it.

@gkalpak
Copy link
Member

gkalpak commented Sep 11, 2018

The behavior is expected. Whether the radios are checked or not (in an AngularJS form) depends on the current value (determined by ngModel) and the radio's associated value (determined by ngValue in your example). Since the 1st and 3rd radios have the same value (because data[0].Title === data[2].Title === 'Test'), whenever the model is set to Test, both radios will be selected (since the model value matches with their associated value).

@emaborsa
Copy link
Author

I get the point.
But why does the first example work?

@gkalpak
Copy link
Member

gkalpak commented Sep 12, 2018

The reason it works (which may not be obvious at first - especially if you are not familiar with scope hierarchies and how prototypal inheritance comes into play), is that ngRepeat creates a new (non-isolate) scope for each clone it stamps out.

So, each td gets its own scope, and thus each ngModel refers to a different thisWorks property (the one on its own scope). So, despite all radios seemingly binding to the same thisWorks property, each one will be bound on a different object (scope) and as such be different than the other ones.

What this actually means, is that they are independent as far as AngularJS is concerned (i.e. all of them could be selected at the same time and clicking the one does not affect the others through ngModel). But because they have the same name attribute, the native browser behavior kicks in and makes them a radio-group (alowing only one to be selected).

However, notice they don't actually work as expected (although they visually seem they do), since thisWorks will still be undefined outside of their own scopes (i.e. in the rest of the template and in your controller).

@emaborsa
Copy link
Author

I knew that ng-repeat creates a new scope. I tought a scope for the iteration itself (1 for each ng-repeat declaration) would be created, not for the single iterated item.
Thanks for the explanation.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants