AngularJS $watchCollection 结合 ng-repeat
AngularJS $watchCollection combined with ng-repeat
如果我直接在 ng-repeat 中使用输入字段,我会在获取列表更改通知时遇到一些问题。否则我可以更改值并从 $watchCollection 获得通知。
一个简化的例子:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.js">
</script>
</head>
<body>
<section ng-app="myApp" ng-controller = "TestController">
<button ng-click = "pushToList()">Add number to list.</button>
<button ng-click = "changeFirstElement()">Change first element.</button>
<textarea ng-model = "log"></textarea>
<ul>
<li ng-repeat="item in list track by $index">
<input ng-model="item"> Value: <span ng-bind="item"></span>
</li>
</ul>
</section>
<script>
angular.module("myApp", [])
.controller("TestController", function($scope){
$scope.log = '';
$scope.list = $scope.list = [1];
$scope.pushToList = function() {
$scope.list.push(Math.random());
}
$scope.changeFirstElement = function() {
$scope.list[0] = Math.random();
}
$scope.$watchCollection(
'list',
function(currentValue, oldValue) {
$scope.log += [
'Current value:',
currentValue.toString(),
'Old value:',
oldValue ? oldValue.toString() : '',
'-----',
'',
].join('\n')
}
)
});
</script>
</body>
</html>
当我通过调用 $scope.list[0] = Math.random();
进行更改时,$watchCollection 执行 "see",但当我使用输入字段时,更改被忽略,或者 $watchCollection "not seen"。为什么是这样?我还能做什么?
而且我知道我可以改用深度 $watch,但我对如何使用 $watchCollection 实现这一点很感兴趣。也因为如果我理解正确的话性能会更好(参见this question)。
编辑:
这是一个plunkr。
当您单击 "Add number to list" 时,$watchCollection 将看到更改并且数组的当前内容被写入文本区域。当您通过单击 "Change first element" 更改第一个数字时,$watchCollection 确实看到发生了更改,并再次将数组中的当前内容写入文本区域。当您使用 ng-repeat 将数组项作为 ng-model 放置在那里的输入字段更改值时。我希望如果我更改输入字段中的值,它会触发与单击 "Change first element" butten 时相同的行为:我希望 $watchCollection 应该看到有变化并且我注册的函数应该写数组的内容到文本区域。但这并没有发生。
问题不在 $watchCollection 中。 ng-repeat 为每个 child 创建范围,因此当您输入时,您仅在 ng-repeat child 范围内更改项目 属性,因为项目是原始的。如果你有 $scope.list=[{value:1}] 你可以改变 parent 范围内的值改变 child 范围内的值,因为 list[0] 和 item 共享相同的引用object。但是 watchCollection 仍然不会被触发,因为它只检测浅层变化。
如果我直接在 ng-repeat 中使用输入字段,我会在获取列表更改通知时遇到一些问题。否则我可以更改值并从 $watchCollection 获得通知。
一个简化的例子:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.js">
</script>
</head>
<body>
<section ng-app="myApp" ng-controller = "TestController">
<button ng-click = "pushToList()">Add number to list.</button>
<button ng-click = "changeFirstElement()">Change first element.</button>
<textarea ng-model = "log"></textarea>
<ul>
<li ng-repeat="item in list track by $index">
<input ng-model="item"> Value: <span ng-bind="item"></span>
</li>
</ul>
</section>
<script>
angular.module("myApp", [])
.controller("TestController", function($scope){
$scope.log = '';
$scope.list = $scope.list = [1];
$scope.pushToList = function() {
$scope.list.push(Math.random());
}
$scope.changeFirstElement = function() {
$scope.list[0] = Math.random();
}
$scope.$watchCollection(
'list',
function(currentValue, oldValue) {
$scope.log += [
'Current value:',
currentValue.toString(),
'Old value:',
oldValue ? oldValue.toString() : '',
'-----',
'',
].join('\n')
}
)
});
</script>
</body>
</html>
当我通过调用 $scope.list[0] = Math.random();
进行更改时,$watchCollection 执行 "see",但当我使用输入字段时,更改被忽略,或者 $watchCollection "not seen"。为什么是这样?我还能做什么?
而且我知道我可以改用深度 $watch,但我对如何使用 $watchCollection 实现这一点很感兴趣。也因为如果我理解正确的话性能会更好(参见this question)。
编辑:
这是一个plunkr。
当您单击 "Add number to list" 时,$watchCollection 将看到更改并且数组的当前内容被写入文本区域。当您通过单击 "Change first element" 更改第一个数字时,$watchCollection 确实看到发生了更改,并再次将数组中的当前内容写入文本区域。当您使用 ng-repeat 将数组项作为 ng-model 放置在那里的输入字段更改值时。我希望如果我更改输入字段中的值,它会触发与单击 "Change first element" butten 时相同的行为:我希望 $watchCollection 应该看到有变化并且我注册的函数应该写数组的内容到文本区域。但这并没有发生。
问题不在 $watchCollection 中。 ng-repeat 为每个 child 创建范围,因此当您输入时,您仅在 ng-repeat child 范围内更改项目 属性,因为项目是原始的。如果你有 $scope.list=[{value:1}] 你可以改变 parent 范围内的值改变 child 范围内的值,因为 list[0] 和 item 共享相同的引用object。但是 watchCollection 仍然不会被触发,因为它只检测浅层变化。