angularjs: ngModel控制器$formatter在元素被移除后仍然会触发
angularjs: ngModel controller $parser & $formatter still fire after element is removed
在下面的例子中,我不明白为什么angular在元素被删除后还会触发解析器和格式化器。我应该在指令中手动清理ngModel控制器吗?如果有,我该怎么做?
要了解我在说什么,请查看柱塞,和
- 打开控制台
- 点击"删除"按钮
- 点击"更改模型"按钮
- 注意格式化程序仍在启动
砰砰作响:http://plnkr.co/edit/R7v5nB8JaQ91WcDGU8BC?p=preview
JS
angular.module('testMod', [])
.controller('testCtrl', function($scope){
$scope.test = "test";
$scope.removeElem = function(id) {
var elem = document.getElementById(id);
angular.element(elem).remove();
}
}).directive('testDir',[function() {
return {
require: 'ngModel',
scope:true,
link: function(scope, elem, attr, ctrl) {
console.log('in directive');
ctrl.$parsers.unshift(function (newValue) {
console.log('directive parser');
return newValue;
});
ctrl.$formatters.unshift(function (newValue) {
console.log('directive formatter');
return newValue;
});
}
}
}]);
HTML
<body ng-controller='testCtrl'>
<input id='test' test-dir ng-model='test'/>
<button ng-click="removeElem('test')">remove</button>
<button ng-click="test = test + 'a'">change model</button>
<div>{{test}}</div>
</body>
你的指令创建了它自己的子作用域——这是一件好事。它拥有它上面所有的$watch,当它的作用域被破坏后,它应该清理自己。
最好的做法是:
-
在设置$watches并计划稍后销毁作用域时创建子作用域或隔离作用域。既然是指令创建了作用域,那么它也应该在必要时销毁它,并释放它所有的$watch。
-
当元素被移除时检测并在必要时销毁作用域。如果您的$watch非常重,并且您不希望它们在指令绑定的元素从DOM中删除时徘徊,那么这样做有时是有意义的。如果删除是临时的,那么这样做可能没有意义-例如,切换元素
的可见性 指令永远不应该破坏属于另一个指令的作用域。也就是说,如果你从父控制器继承了作用域,那么让父控制器自己清理——这不是子指令的工作。
如果指令设置了$watch,它应该监听$destroy事件,这样它就可以注销它们。
如果指令用on()注册了任何javascript事件监听器,它应该在作用域被销毁时用off()注销它们。
当一个元素被从DOM中删除时,可以通过处理jQuery元素本身的$destroy事件来执行清理:
// creates a child scope owned by the directive
scope: true,
link: function(scope, element, attr) {
// set up a click handler
element.on('click', function() {
...
});
// set up a $watch on the child scope. It returns a
// function that you can call to unregister the $watch
var unregister = scope.$watch('test', function() {
...
});
// when the element is removed from the DOM,
// destroy the scope and all its $watches.
element.on('$destroy', function() {
// remove the $watch
unregister();
// remove the click handler
element.off('click');
// call $destroy on the child scope
// so that it can propagate to any children
scope.$destroy();
});
}
您不应该必须在ng-model之后进行清理。当$destroy事件被传播到子作用域时,它将自己清理。如果所有的指令都在它们自己之后进行清理,那么当涉及到内存泄漏和孤立的$watch时,就会少得多的担心。
这是一个更新的Plunker,当元素被删除时清理它的$watches
https://docs.angularjs.org/guide/directive根据AngularJS Docs
我们注册一个事件元素。("美元毁灭",…)。是什么触发的?美元毁灭事件吗?
AngularJS会发出一些特殊的事件。当一个DOM节点已经被Angular编译器编译过的代码会被销毁,它会发出$destroy事件。类似地,当AngularJS的作用域被销毁时,它也会被销毁广播$destroy事件到监听范围。
通过监听此事件,您可以删除可能导致内存泄漏。向作用域和元素注册的侦听器是当它们被破坏时会自动清理,但是如果你在服务上注册侦听器,或者在DOM上注册侦听器节点中没有被删除的节点,您必须自己清理它,或者您可能会引入内存泄漏。
最佳实践:指令应该自己清理。你可以使用元素。On ('$destroy',…)或作用域。$on('$destroy',…删除指令时的清理功能。
在销毁,我猜你可以直接"注销"
elem.on('$destroy', function() {
ctrl.$parsers.shift();
ctrl.$formatters.shift()
alert('ok');
});
- 在指令控制器中使用$attrs时出现问题
- 有没有任何方法可以将控制器从文件加载到ui路由器$stateProvider中
- 从控制器返回后Ajax启动事件激发
- 获取@ResponseBody的一部分作为主干和Spring MVC控制器之间的参数
- 如何在单击复选框后调用控制器方法
- 在控制器和数据对象之间同步数据
- 将Javascript数组发送到控制器ASP.NET MVC
- 角度控制器结构
- 如何在Jquery中发布后将值从视图返回到控制器
- 缺少 Angular JS 必需控制器错误:找不到指令所需的控制器“ngModel”
- 如何在控制器中获取输入的ngModel
- 角度 UI/引导类型提前显示“错误:无控制器:ngModel”错误
- ngModel 在控制器中更新,但不在视图中更新,角度 2
- ngSubmit和ngDisabled不工作,但ngModel已绑定到控制器
- angularjs: ngModel控制器$formatter在元素被移除后仍然会触发
- 在angularJs中从控制器中绑定ngModel,或者从ngModel中调用函数
- 在控制器中获取ngModel值- AngularJS
- AngularJS:将ngModel从控制器传递到指令
- 从控制器以编程方式改变ngModel的值
- 使用来自控制器的ngModel setViewValue