31

我正在学习 angularjs,我希望能够让用户输入许多输入。输入这些输入时,list数组元素应相应更改。我想尝试使用 ngRepeat 指令,但我读到了,因为它创建了一个新范围,我无法进行数据绑定:

<div ng-repeat="item in list">
    <label>Input {{$index+1}}:</label>
    <input ng-model="item" type="text"/>
</div>

我想知道是否应该使用自定义指令来执行此操作或以不同的方式处理它。

4

5 回答 5

88

数据绑定到原始“项目”不起作用的原因是 ng-repeat 为每个项目创建子范围的方式。对于每个项目,ng-repeat 都有新的子范围原型继承自父范围(见下图中的虚线),然后它将项目的值分配给子范围上的新属性(下图中的红色项目)。新属性的名称是循环变量的名称。从ng-repeat 源代码

childScope = scope.$new();
...
childScope[valueIdent] = value;

如果 item 是原语,则新的子范围属性本质上被分配了原语值的副本。此子范围属性对父范围不可见,您对输入字段所做的更改存储在此子范围属性中。例如,假设我们在父范围内

$scope.list = [ 'value 1', 'value 2', 'value 3' ];

在 HTML 中:

<div ng-repeat="item in list">

然后,第一个子作用域将具有以下item属性,具有原始值 ( value 1):

item: "value 1"

使用原语重复 ng-repeat

由于 ng-model 数据绑定,您对表单输入字段所做的更改存储在该子范围属性中。

您可以通过将子范围记录到控制台来验证这一点。在 ng-repeat 中添加到您的 HTML:

<a ng-click="showScope($event)">show scope</a>

添加到您的控制器:

$scope.showScope = function(e) {
    console.log(angular.element(e.srcElement).scope());
}


使用@Gloopy 的方法,每个子作用域仍然获得一个新的“item”属性,但是因为 list 现在是一个对象数组,childScope[valueIdent] = value;导致 item 属性的值被设置为对其中一个数组对象的引用(而不是副本)。

ng-repeat 对象

使用 showScope() 技术,您将看到子范围item属性的值引用了数组对象之一——它不再是原始值。

另请参阅不要绑定到 ng-repeat 子范围中的原语
AngularJS 中范围原型/原型继承的细微差别是什么?(其中包含使用 ng-repeat 时范围的图片)。

于 2012-12-08T22:40:36.207 回答
37

如果你list是一个对象数组(而不是一个基元数组),你会有更好的运气。即使使用以下命令创建了新范围,这也可以正常工作ng-repeat

<div ng-repeat="item in list">
    <label>Input {{$index+1}}:</label>
    <input ng-model="item.value" type="text"/>
</div>

控制器:

function TestController($scope) {
    $scope.list = [ { value: 'value 1' }, { value: 'value 2' }, { value: 'value 3' } ];
}​

这个小提琴为例。

另一方面,如果您尝试绑定到字符串数组,则新范围将导致问题,因为您正在修改的值不会与原始数组字符串原语绑定(如this fiddle example)。

于 2012-10-19T15:57:18.680 回答
3

我找到了一种有趣的方法,它允许我处理一组原语。

我正在使用 AngularJS 1.2.1,这是我可以使它工作的唯一版本。

HTML:

<div ng-repeat="item in list">
    <label>Input {{$index+1}}:</label>
    <input ng-model="item" type="text" ng-blur="editItem($index, item)"/>
</div>

JavaScript:

$scope.editItem = function(idx, eItem) {
    $scope.list[idx] = eItem;
};

链接: http: //jsfiddle.net/bxD2P/10/(感谢 Gloopy 提供的初学者 Fiddle)

我确信有一些简单的方法可以在它的工作原理上找到漏洞,我很想听听他们的意见。它可以让我支持我的代码。

于 2014-10-09T17:50:24.543 回答
1

考虑使用ngList指令https://docs.angularjs.org/api/ng/directive/ngList

于 2014-04-24T11:16:31.240 回答
1

这是一种方法。我对我的转发器使用了 textareas 和不同的结构,但主要概念是:

  • 根据索引显示一个简单的值。(未绑定)
  • 模糊更新模型
  • 模型更新重新渲染

它本质上是伪造绑定。

工作小提琴 - http://jsfiddle.net/VvnWY/4/

的HTML:

  <script type="text/ng-template" id="textareas.html">
    <textarea ng-if="strings" ng-repeat="str in strings" ng-blur="blur( $event, $index )">{{strings[$index]}}</textarea>
  </script>

<div ng-controller="MyCtrl">
    Here's a few strings: <br />
    <div ng-repeat="str in strings">{{strings[$index]}}</div>

    Here's the strings as editable (twice so that you can see the updates from a model change): <br />
    <form-textareas strings="strings"></form-textareas>
    <form-textareas strings="strings"></form-textareas>

</div>

JS:

var myApp = angular.module('myApp',[]);
angular.module('myApp', [])
  .controller('MyCtrl', ['$scope', function($scope) {
    $scope.strings = [ "foo", "bar", "cow" ];
   }])
  .directive('formTextareas', function() {
    return {
        restrict: "E",
        scope: {
            strings: '='
        },
        templateUrl: "textareas.html",
        link: function( $scope ){
            $scope.blur = function( $event, $index ){
                $scope.strings[ $index ] = $event.currentTarget.value;
            };
        }
    };
  })
;
于 2014-04-12T21:22:49.750 回答