You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ng-repeat绑定对象到单选按钮组时失效的原因排查

为什么AngularJS中ng-repeat会导致单选按钮的对象绑定失效?

先来看你给出的两个示例:

示例1(绑定失效的情况)

JavaScript代码

angular
  .module('listParser', [])
  .factory('Item', function() {
    return function(id, name) {
      this.id = id;
      this.name = name;
    }
  })
  .controller('default', ['$scope', 'Item', function($scope, Item) {
    var collection = [];
    collection.push(new Item(0, 'Alpha'));
    collection.push(new Item(1, 'Beta'));
    $scope.collection = collection;
    $scope.lucky = collection[0];
  }]);

HTML代码

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="listParser" ng-controller="default">
  <div class="radio-group">
    <ul>
      <li ng-repeat="item in collection">
        <input type="radio" name="group" ng-value="item" ng-model="lucky"/>
      </li>
    </ul>
  </div>
  <div class="description">
    {{lucky.name}}
  </div>
</div>

示例2(绑定正常的情况)

JavaScript代码

angular
  .module('listParser', [])
  .factory('Item', function() {
    return function(id, name) {
      this.id = id;
      this.name = name;
    }
  })
  .controller('default', ['$scope', 'Item', function($scope, Item) {
    var collection = [];
    collection.push(new Item(0, 'Alpha'));
    collection.push(new Item(1, 'Beta'));
    $scope.collection = collection;
    $scope.lucky = collection[0];
  }]);

HTML代码

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="listParser" ng-controller="default">
  <div class="radio-group">
    <ul>
      <li><input type="radio" name="group" ng-value="collection[0]" ng-model="lucky"/></li>
      <li><input type="radio" name="group" ng-value="collection[1]" ng-model="lucky"/></li>
    </ul>
  </div>
  <div class="description">
    {{lucky.name}}
  </div>
</div>

问题原因:ng-repeat的子作用域特性

这个问题我之前也碰到过,本质是AngularJS里ng-repeat的作用域特性在搞鬼!

ng-repeat会为每一个迭代项创建一个独立的子作用域,这些子作用域通过原型链继承自父控制器的作用域。当你在ng-repeat里使用ng-model="lucky"时,单选按钮被选中的瞬间,AngularJS会尝试给当前作用域的lucky属性赋值。但这里有个关键:当你直接给作用域上的属性赋值时,Angular不会去原型链上查找父作用域的同名属性,而是直接在当前子作用域新建一个lucky属性。

这样一来,子作用域的lucky和父控制器作用域的lucky就变成了两个完全独立的变量!你选单选按钮时修改的是子作用域里的lucky,而页面上{{lucky.name}}绑定的是父作用域的lucky,自然看不到变化。

而示例2里没有用ng-repeat,所有元素都在父控制器的作用域下,ng-model="lucky"直接绑定的就是父作用域的变量,所以修改能正常同步。

解决方案:使用“点语法”绑定对象属性

解决这个问题的经典方案就是不要直接绑定作用域上的独立对象,而是绑定一个对象的属性,也就是Angular里常说的“点语法”。

修改你的控制器代码,把lucky放到一个对象里:

angular
  .module('listParser', [])
  .factory('Item', function() {
    return function(id, name) {
      this.id = id;
      this.name = name;
    }
  })
  .controller('default', ['$scope', 'Item', function($scope, Item) {
    var collection = [];
    collection.push(new Item(0, 'Alpha'));
    collection.push(new Item(1, 'Beta'));
    $scope.collection = collection;
    // 把lucky放到model对象里
    $scope.model = {
      lucky: collection[0]
    };
  }]);

然后修改HTML里的ng-model:

<div ng-app="listParser" ng-controller="default">
  <div class="radio-group">
    <ul>
      <li ng-repeat="item in collection">
        <input type="radio" name="group" ng-value="item" ng-model="model.lucky"/>
      </li>
    </ul>
  </div>
  <div class="description">
    {{model.lucky.name}}
  </div>
</div>

这样做的原理是:子作用域通过原型链访问model对象时,不会创建新的model属性,而是直接修改父作用域model对象里的lucky属性,从而实现数据的双向绑定同步。

内容的提问来源于stack exchange,提问作者Lordbalmon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:48:53