angularjs:ngModel控制器$解析器和放大器; $格式化仍然火元素后删除 [英] angularjs: ngModel controller $parser & $formatter still fire after element is removed

查看:129
本文介绍了angularjs:ngModel控制器$解析器和放大器; $格式化仍然火元素后删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的exmple,我不明白为什么角仍在射击的解析器和格式化的元素被删除了。我应该在指令中手动清理ngModel控制器?如果是这样,我应该怎么做呢?

要明白我在说什么,检查出plunker,以及


  1. 打开控制台

  2. 点击删除按钮

  3. 单击更改模式按钮

  4. 注意格式化仍然射击

plunker:<一href=\"http://plnkr.co/edit/R7v5nB8JaQ91WcDGU8BC?p=$p$pview\">http://plnkr.co/edit/R7v5nB8JaQ91WcDGU8BC?p=$p$pview

JS

  angular.module('testMod',[])
.controller('testCtrl',函数($范围){
  $ scope.test =测试;
  $ scope.removeElem =功能(ID){
    VAR ELEM =的document.getElementById(id)的;
    angular.element(ELEM)一个.remove();
  }
})指令(TESTDIR',[功能(){
  返回{
    要求:'ngModel',
    适用范围:真,
    链接:功能(范围,ELEM,ATTR,CTRL){
      的console.log('的指令);
      Ctrl键。$ parsers.unshift(功能(newValue)以{
          的console.log('指令语法分析器');
          返回为newValue;
      });
      Ctrl键。$ formatters.unshift(功能(newValue)以{
          的console.log('指令格式');
          返回为newValue;
      });
    }
  }
}]);

HTML

 &LT;机身NG控制器='testCtrl'&GT;
    &LT;输入ID =测试测试DIR NG-模式='测试'/&GT;
    &LT;按钮NG点击=removeElem('测试')&GT;删除&LT; /按钮&GT;
    &LT;按钮NG点击=测试=测试+'A'&GT;变化模型&LT; /按钮&GT;
    &LT; D​​IV&GT; {{}测试}&LT; / DIV&GT;
&LT; /身体GT;


解决方案

您指令创建自己的子范围 - 这是一件好事。它拥有在其上的所有$手表,当它的范围被摧毁后,本身就应该清理。

这是很好的做法:


  1. 创建一个孩子,或者当您设置$手表,打算稍后破坏范围隔离范围。由于指令创建的范围,这也应该是一个在必要时摧毁它,并释放所有的$手表。


  2. 当被删除的元素的检测并在必要时破坏的范围。有时候,这是有道理的,如果你的$的手表是沉重做的,你不想的时候从DOM删除的指令所绑定的元素他们游逛。这可能是没有意义做的,如果去除是暂时的 - 即元素的可见性切换


  3. 一个指令,不应该破坏属于另一个范畴。即如果你继承了父控制器范围然后让父控制器清理后本身 - 它是不是孩子指令的工作做


  4. 如果该指令已设立任何$手表,它应该监听范围$破坏事件,以便它可以注销它们。


  5. 如果该指令已注册的任何JavaScript事件侦听器对(),它应该关闭()时的范围被销毁注销它们。


有可能进行清理时,一个元素是从DOM通过处理$的的 jQuery的元素破坏事件删除的本身:

  //创建了一个由指令所拥有的子作用域
适用范围:真,
链接:功能(范围,元素,属性){    //设置点击处理程序
    element.on('点击',功能(){
        ...
    });    //设置对孩子范围$手表。它返回一个
    //你可以调用函数来注销$腕表
    VAR注销=范围。$表(测试,函数(){
         ...
    });    //当元件被从DOM除去
    //破坏的范围及其所有$手表。
     element.on('$破坏',函数(){
          //删除$腕表
          注销();          //删除单击处理程序
          element.off('点击');          //调用$摧毁孩子的范围
          //以便它可以传播到任何的儿童
          。范围$ destroy()方法;
     });
}

您的不该后有NG-模型进行清理。当$破坏事件被传播到子作用域将清理后本身。如果自己以后所有指令都清理了,会有少了很多担心,当涉及到内存泄漏和孤儿$手表。

下面是一个更新的 Plunker 来清理其$手表,当元素被删除

In the exmple below, I don't understand why angular is still firing the parsers and formatters after the element is removed. Should I be cleaning up the ngModel controller manually within the directive? If so, how should I do that?

To see what I'm talking about, check out the plunker, and

  1. open a console
  2. click the 'remove' button
  3. click the 'change model' button
  4. notice the formatter still firing

plunker: 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>

解决方案

Your directive creates its own child scope - that's a good thing. It owns all the $watches on it, and should clean up after itself when its scope is destroyed.

It is good practice to:

  1. Create a child or isolate scope when you set up $watches and plan to destroy the scope later. Since the directive created the scope, it should also be the one to destroy it when necessary and release all its $watches.

  2. Detect when the element is being removed and destroy the scope if necessary. Sometimes this makes sense to do if your $watches are heavy, and you don't want them hanging around when the element that the directive is bound to is removed from the DOM. This may not make sense to do if the removal is temporary - i.e. toggle visibility of an element

  3. A directive should never destroy a scope belonging to another. i.e if you inherited the scope from the parent controller then let the parent controller clean up after itself - it is not the job of the child directive to do it.

  4. If the directive has set up any $watches, it should listen for the scope $destroy event so that it can unregister them.

  5. If the directive has registered any javascript event listeners with on(), it should unregister them with off() when the scope is destroyed.

It is possible to perform clean-up when an element is removed from the DOM by handling the $destroy event on the jQuery element itself:

// 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();
     });
}

You should not have to clean up after ng-model. It will clean up after itself when the $destroy event is propagated to the child scopes. If all directives cleaned up after themselves, there would be a lot less to worry about when it comes to memory leaks and orphaned $watches.

Here is an updated Plunker that cleans up its $watches when the element is removed.

这篇关于angularjs:ngModel控制器$解析器和放大器; $格式化仍然火元素后删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆