我通过ng-repeat循环渲染数据。我想在更新阵列时更新它。从我读到的,这应该自动发生,但这不起作用。我做错了什么?
html:
<tr ng-repeat="data in dataDifferenceArray">
<td>
{{data.name}}
</td>
<td>
{{data.startData}}
</td>
<td>
{{data.endData}}
</td>
<td>
{{data.differenceData}}
</td>
</tr>
控制器(此功能在按钮点击时触发):
$scope.getDifferences = function () {
$scope.dataDifferenceArray = [];
var i;
for (i = 0; i < 20 ;i++) {
$scope.dataDifferenceArray.push({
name : 30,
startData : 20,
endData : 2,
differenceData : 30
})
}
}
Console.log显示数组已正确更新,但我视图中的表不会更改。我不知道我做错了什么。
答案 0 :(得分:53)
那是因为您更改了方法getDifferences
中的数组引用。
为避免这种情况,我们点,例如使用“控制器为”语法:
<div ng-controller="myController as c">
[...]
<tr ng-repeat="data in c.dataDifferenceArray">
<td>
{{data.name}}
</td>
<td>
{{data.startData}}
</td>
<td>
{{data.endData}}
</td>
<td>
{{data.differenceData}}
</td>
</tr>
[...]
如果你想了解范围是如何工作的,我会建议这篇文章:https://github.com/angular/angular.js/wiki/Understanding-Scopes#ngRepeat
另一种解决方案可能是:
$scope.getDifferences = function () {
$scope.dataDifferenceArray.length = 0; // here ----
var i;
for (i = 0; i < 20 ;i++) {
$scope.dataDifferenceArray.push({
name : 30,
startData : 20,
endData : 2,
differenceData : 30
})
}
}
但在此解决方案中,您需要在外部创建数组(并且只需创建一次):$scope.dataDifferenceArray = [];
编辑2:我的回答并不是很清楚,让我们试着深入了解正在发生的事情:
问: 为什么ng-repeat仍然有引用REFERENCE1?
您必须记住模板中不仅有1个范围。
例如:ng-repeat
指令为每个重复元素创建新范围,但我们仍然可以访问每个子范围中的父范围。 Angular使用原型继承实现了这种行为:由于其原型,每个子范围都继承其父范围的属性。
您可以通过检查子元素上的元素来测试它的工作方式,然后在控制台中输入:$($0).scope()
(它将为您提供所选元素的范围,$0
是所选元素(铬))。您现在可以看到$($0).scope().$parent
和$($0).scope().__proto__
中存在相同的对象,它是您的父作用域。
但是原型继承存在一个问题:假设我们A = {}; B = {C: 1}
,A
继承自B
然后A.C == 1
。但是,如果我们影响新值A.C = 2
,我们就不会更改B
,只会更改A
。
使用当前作用域this
评估角度表达式。因此,如果我们有类似ng-click="dataDifferenceArray = []"
的内容,则相当于this.dataDifferenceArray = []
,其中this
是ng-click
所在元素的范围。
当您使用 controller-as 时会解决此问题,因为它会在范围内注入控制器,并且您永远不会直接影响范围的属性。
让我们回顾一下我们的示例:A = {}; B = {C: {D: 1}}
,如果A
继承自B
,那么A.C.D == 1
。现在即使我们影响了新值A.C.D = 2
,我们也改变了B
。
答案 1 :(得分:15)
即使正确更新数组引用,我也遇到了同样的问题,ng-repeat没有呈现我的更改。最后,我通过调用$ scope。$ apply();
找到了解决方案$window.wizard.on("readySubmit", function () {
var newArray = GenesisFactory.GetPermissionsFromTemplate(GenesisFactory.SecurityModules, true);
$scope.NewSecurityProfileInstance.Permission.length = 0;
newArray.forEach(function (entry) {
$scope.NewSecurityProfileInstance.Permission.push(entry);
});
$scope.$apply();
});
我希望这可以提供帮助。
答案 2 :(得分:5)
我没有做任何事情,只是添加了这一行&#34; $ scope。$ apply() &#34;推完元素之后,我就完成了。
答案 3 :(得分:3)
对于那些在范围内设置数组的人(即$scope.$apply()
如果在推送后调用会导致错误),但仍无法在DOM上正确更新,我的解决方法在推/片/数组更新后立即调用此函数:
function applyArray(container, key) {
setTimeout(function() {
var tempArray = container[key];
container[key] = [];
$scope.$apply();
container[key] = tempArray;
$scope.$apply();
}, 0);
}
通过传递container
和key
,container
在这种情况下$scope
和key
将是"dataDifferenceArray"
(注意引号)。
我不知道为什么在某些情况下DOM没有正确更新。它显示了正确的元素数量,并且在添加新元素时更新,它只是不正确地更新子元素DOM(即新推送的元素可以采用前一个子元素的DOM视图)。这可能是由于我们如何在Johnpapa's Angular Style Guide中将this
重新定义为vm
,但我对此并不自信。
答案 4 :(得分:0)
实际上看起来你的数组在click函数中被设置为空。如果将数组范围移到函数外部,这将起作用。
实施例
// Declared outside
$scope.dataDifferenceArray = [];
// Your function
$scope.getDifferences = function () {
var i;
for (i = 0; i < 20 ;i++) {
$scope.dataDifferenceArray.push({
name : 30,
startData : 20,
endData : 2,
differenceData : 30
});
}
};