AngularJS:从模型数组拼接模型元素时,不会更新 ng-repeat 列表
Posted
技术标签:
【中文标题】AngularJS:从模型数组拼接模型元素时,不会更新 ng-repeat 列表【英文标题】:AngularJS: ng-repeat list is not updated when a model element is spliced from the model array 【发布时间】:2013-03-06 17:12:53 【问题描述】:我有两个控制器,并通过 app.factory 函数在它们之间共享数据。
单击链接时,第一个控制器会在模型数组 (pluginsDisplayed) 中添加一个小部件。小部件被推送到数组中,并且此更改反映到视图中(使用 ng-repeat 显示数组内容):
<div ng-repeat="pluginD in pluginsDisplayed">
<div k2plugin pluginname="pluginD.name" pluginid="pluginD.id"></div>
</div>
该小部件建立在三个指令之上:k2plugin、remove 和 resize。 remove 指令将跨度添加到 k2plugin 指令的模板。当单击所述跨度时,共享数组中的右侧元素将被删除为Array.splice()
。共享数组已正确更新,但更改未反映在视图中。但是,当添加另一个元素时,删除后,视图会正确刷新,并且不会显示先前删除的元素。
我做错了什么?你能解释一下为什么这不起作用吗? 有没有更好的方法来做我想要用 AngularJS 做的事情?
这是我的 index.html:
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js">
</script>
<script src="main.js"></script>
</head>
<body>
<div ng-app="livePlugins">
<div ng-controller="pluginlistctrl">
<span>Add one of pluginList.length plugins</span>
<li ng-repeat="plugin in pluginList">
<span><a href="" ng-click="add()">plugin.name</a></span>
</li>
</div>
<div ng-controller="k2ctrl">
<div ng-repeat="pluginD in pluginsDisplayed">
<div k2plugin pluginname="pluginD.name" pluginid="pluginD.id"></div>
</div>
</div>
</div>
</body>
</html>
这是我的 main.js:
var app = angular.module ("livePlugins",[]);
app.factory('Data', function ()
return pluginsDisplayed: [];
);
app.controller ("pluginlistctrl", function ($scope, Data)
$scope.pluginList = [name: "plugin1", name:"plugin2", name:"plugin3"];
$scope.add = function ()
console.log ("Called add on", this.plugin.name, this.pluginList);
var newPlugin = ;
newPlugin.id = this.plugin.name + '_' + (new Date()).getTime();
newPlugin.name = this.plugin.name;
Data.pluginsDisplayed.push (newPlugin);
)
app.controller ("k2ctrl", function ($scope, Data)
$scope.pluginsDisplayed = Data.pluginsDisplayed;
$scope.remove = function (element)
console.log ("Called remove on ", this.pluginid, element);
var len = $scope.pluginsDisplayed.length;
var index = -1;
// Find the element in the array
for (var i = 0; i < len; i += 1)
if ($scope.pluginsDisplayed[i].id === this.pluginid)
index = i;
break;
// Remove the element
if (index !== -1)
console.log ("removing the element from the array, index: ", index);
$scope.pluginsDisplayed.splice(index,1);
$scope.resize = function ()
console.log ("Called resize on ", this.pluginid);
)
app.directive("k2plugin", function ()
return
restrict: "A",
scope: true,
link: function (scope, elements, attrs)
console.log ("creating plugin");
// This won't work immediately. Attribute pluginname will be undefined
// as soon as this is called.
scope.pluginname = "Loading...";
scope.pluginid = attrs.pluginid;
// Observe changes to interpolated attribute
attrs.$observe('pluginname', function(value)
console.log('pluginname has changed value to ' + value);
scope.pluginname = attrs.pluginname;
);
// Observe changes to interpolated attribute
attrs.$observe('pluginid', function(value)
console.log('pluginid has changed value to ' + value);
scope.pluginid = attrs.pluginid;
);
,
template: "<div>pluginname <span resize>_</span> <span remove>X</span>" +
"<div>Plugin DIV</div>" +
"</div>",
replace: true
;
);
app.directive("remove", function ()
return function (scope, element, attrs)
element.bind ("mousedown", function ()
scope.remove(element);
)
;
);
app.directive("resize", function ()
return function (scope, element, attrs)
element.bind ("mousedown", function ()
scope.resize(element);
)
;
);
【问题讨论】:
【参考方案1】:每当您在 AngularJS 之外进行某种形式的操作时,例如使用 jQuery 进行 Ajax 调用,或者将事件绑定到您在此处的元素,您需要让 AngularJS 知道要更新自己。这是您需要做的代码更改:
app.directive("remove", function ()
return function (scope, element, attrs)
element.bind ("mousedown", function ()
scope.remove(element);
scope.$apply();
)
;
);
app.directive("resize", function ()
return function (scope, element, attrs)
element.bind ("mousedown", function ()
scope.resize(element);
scope.$apply();
)
;
);
这是关于它的文档:https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply
【讨论】:
考虑在传递给 $apply 的表达式/函数中移动 scope.remove(element) 和 scope.resize(element)。 @PerHornshøj-Schierbeck 我同意,否则如果发生错误,Angular 将不会意识到错误。 小心!通常,Angular 在必要时会调用摘要循环,而 $apply 将手动调用它。手动调用它通常是一种不好的做法,因为我们可能会犯优化错误,并且可能会消耗资源。 我不明白删除或调整大小的内容是什么。【参考方案2】:如果您在$scope.pluginsDisplayed.splice(index,1);
之后添加$scope.$apply();
,那么它可以工作。
我不确定为什么会这样,但基本上当 AngularJS 不知道 $scope 已更改时,它需要手动调用 $apply。我也是 AngularJS 的新手,所以无法更好地解释这一点。我也需要深入研究一下。
我发现this awesome article 解释得非常恰当。 注意:我认为使用 ng-click (docs) 而不是绑定到“mousedown”可能会更好。我在这里基于 AngularJS 编写了一个简单的应用程序(http://avinash.me/losh,源代码http://github.com/hardfire/losh)。它不是很干净,但它可能会有所帮助。
【讨论】:
【参考方案3】:我有同样的问题。问题是因为“ng-controller”被定义了两次(在路由和 HTML 中)。
【讨论】:
【参考方案4】:从 ng-repeat 中删除“按索引跟踪”,它会刷新 DOM
【讨论】:
【参考方案5】:有一个简单的方法可以做到这一点。很容易。因为我注意到了
$scope.yourModel = [];
删除您可以这样做的所有 $scope.yourModel 数组列表
function deleteAnObjectByKey(objects, key)
var clonedObjects = Object.assign(, objects);
for (var x in clonedObjects)
if (clonedObjects.hasOwnProperty(x))
if (clonedObjects[x].id == key)
delete clonedObjects[x];
$scope.yourModel = clonedObjects;
$scope.yourModel 将使用 clonedObjects 进行更新。
希望对您有所帮助。
【讨论】:
以上是关于AngularJS:从模型数组拼接模型元素时,不会更新 ng-repeat 列表的主要内容,如果未能解决你的问题,请参考以下文章
在angularjs中选中checkall和checkbox时,推送并拼接成数组