AngularJS中ng-repeat生成的单选按钮点击后无法通过按钮切换的原因
问题:ng-repeat生成的单选按钮点击后无法通过外部按钮选中
这段代码创建了两组各3个单选按钮:一组为单独定义的单选按钮,另一组通过ng-repeat指令构建。两组单选按钮初始均可通过点击A-C按钮或直接点击单选按钮本身选中,但点击过ng-repeat生成的单选按钮后,就无法再通过A-C按钮选中它们了,请问这是什么原因?
原代码
JavaScript部分
angular.module('radioExample', []) .controller('ExampleController', ['$scope', function($scope) { $scope.color = { name: 'blue' }; $scope.radiomodel = 'blue'; $scope.radiovalues = ['red', 'green', 'blue']; $scope.clickA = function() { $scope.color.name = 'red'; $scope.radiomodel = 'red'; } $scope.clickB = function() { $scope.color.name = 'green'; $scope.radiomodel = 'green'; } $scope.clickC = function() { $scope.color.name = 'blue'; $scope.radiomodel = 'blue'; } $scope.radioclick = function(index) { $scope.clickvalue = index; } $scope.radiochange = function(index) { $scope.changevalue = index; } }]);
HTML部分
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script> <body ng-app="radioExample"> <form name="myForm" ng-controller="ExampleController"> <button ng-click="clickA()">A</button> <button ng-click="clickB()">B</button> <button ng-click="clickC()">C</button> <br/> individual <br/> <label> <input type="radio" ng-model="color.name" value="red"> Red </label><br/> <label> <input type="radio" ng-model="color.name" value = "green"> Green </label><br/> <label> <input type="radio" ng-model="color.name" value="blue"> Blue </label><br/> ng-repeat <div ng-repeat="i in [0, 1, 2]"> <input type="radio" name="myradio" value="{{radiovalues[$index]}}" ng-model="radiomodel" ng-click="radioclick($index)" ng-change="radiochange($index)"> {{$index}} ({{radiovalues[$index]}}) </input> </div> <tt>color = {{color.name | json}}</tt><br/> </form> </body>
原因分析
核心问题是ng-repeat会创建独立的子作用域,且AngularJS对原始类型(字符串、数字、布尔值)的绑定是值传递而非引用传递:
- 初始状态下,ng-repeat的子作用域继承父作用域的
radiomodel值,外部按钮修改父作用域的radiomodel时,子作用域能同步获取到值,单选按钮正常选中。 - 当直接点击ng-repeat内的单选按钮时,AngularJS会在当前子作用域中创建一个
radiomodel的副本(无法直接修改父作用域的原始类型变量),此时子作用域的radiomodel和父作用域的radiomodel变成两个完全独立的变量。 - 后续点击A-C按钮,修改的只是父作用域的
radiomodel,但ng-repeat内的单选按钮绑定的是子作用域的副本,自然不会同步更新。
解决方案
遵循AngularJS的**"点规则"**,将原始类型的模型包装成对象属性,利用引用传递的特性让子作用域直接修改父作用域的变量:
- 修改控制器代码:把
radiomodel改成对象属性
angular.module('radioExample', []) .controller('ExampleController', ['$scope', function($scope) { $scope.color = { name: 'blue' }; // 用对象包裹模型 $scope.radioData = { model: 'blue' }; $scope.radiovalues = ['red', 'green', 'blue']; $scope.clickA = function() { $scope.color.name = 'red'; $scope.radioData.model = 'red'; } $scope.clickB = function() { $scope.color.name = 'green'; $scope.radioData.model = 'green'; } $scope.clickC = function() { $scope.color.name = 'blue'; $scope.radioData.model = 'blue'; } $scope.radioclick = function(index) { $scope.clickvalue = index; } $scope.radiochange = function(index) { $scope.changevalue = index; } }]);
- 修改HTML中的ng-model绑定:
<div ng-repeat="i in [0, 1, 2]"> <input type="radio" name="myradio" value="{{radiovalues[$index]}}" ng-model="radioData.model" ng-click="radioclick($index)" ng-change="radiochange($index)"> {{$index}} ({{radiovalues[$index]}}) </input> </div>
这样修改后,无论点击外部按钮还是直接点击单选按钮,操作的都是同一个对象的属性,不会出现作用域变量分离的问题,单选按钮的状态就能正常同步了。
内容的提问来源于stack exchange,提问作者notangularjsexpert
相关产品推荐
相关产品推荐

