我正在学习angularjs,我希望能够让用户输入许多输入。输入这些输入后,list
数组元素应相应更改。我想尝试使用ngRepeat指令,但我读到它,因为它创建了一个新的范围,我无法数据绑定:
<div ng-repeat="item in list">
<label>Input {{$index+1}}:</label>
<input ng-model="item" type="text"/>
</div>
我想知道我是否应该使用自定义指令来执行此操作或以不同方式处理它。
答案 0 :(得分:87)
数据绑定到基元“item”的原因不起作用的原因是ng-repeat为每个项创建子范围的方式。对于每个项目,ng-repeat使新的子范围原型继承自父范围(参见下图中的虚线),然后它将项目的值分配给子范围上的新属性(下图中的红色项目)。新属性的名称是循环变量的名称。来自ng-repeat source code:
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-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属性的值被设置为对其中一个数组对象的引用(不是副本)。
使用showScope()技术,您将看到子范围item
属性的值引用其中一个数组对象 - 它不再是原始值。
另见don't bind to primitives in ng-repeat child scopes和
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?(其中包含使用ng-repeat时范围的图片)。
答案 1 :(得分: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作为示例。
另一方面,如果您尝试绑定到字符串数组,新范围将导致问题,因为您正在修改的值将不会绑定到原始数组字符串基元(如this fiddle示例中所示)。
答案 2 :(得分: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为首发小提琴)
我确信有很多简单的方法可以解释它是如何工作的,我很乐意听到它们。它可以让我支持我的代码。
答案 3 :(得分: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;
};
}
};
})
;
答案 4 :(得分:1)