仍广播到被破坏的控制器范围angularjs

时间:2017-06-29 15:22:17

标签: javascript angularjs

我有一个指令,它的回调如下:

function Callback(){
    return {
      templateUrl: 'somePath',
      scope: true,
      link: function(scope, el) {
        scope.cancel = function(){
          el.remove()
          scope.$destroy()
        }
      },
      controller: 'someController',
      controllerAs: 'vm'
    }
  }

link方法只是添加了一个从DOM中删除指令的cancel方法。

在指令控制器中我正在侦听一个事件:

$rootScope.$on('parent', function(){
  someService.addToArray(someData)
})

此方法只是将数据推送到数组。

在父控制器和视图中,这个指令正在被利用,我实际上正在解雇广播。父控制器的一部分:

var vm = this
vm.broadcastEvent = broadcastEvent      
function broadcastEvent(){
  $rootScope.$broadcast('someEvent', 'someData')
}

在视图中我有一些可点击的div激发了这个方法。

它工作得很好,该指令会在删除元素并销毁范围之前听到广播并将数据添加到数组中。

问题是,在我调用.cancel之后,该元素被删除,并且可能是范围被破坏,但它仍然会向数组添加数据。我错过了scope.$destroy()的工作原理吗?

我可以通过取消注册$on来获得我想要的行为,我是否只需要这样做?我想问题是,是否会破坏控制器范围否定其中定义的任何$on,或者您是否需要确保在销毁范围之前明确取消注册。

2 个答案:

答案 0 :(得分:1)

监听器函数在$ rootScope上注册,并且在指令$ scope被销毁后仍然存在:

$rootScope.$on('parent', function listener(){
  someService.addToArray(someData)
})

该控制器需要保存调用$ rootScope返回的注销函数。$ on方法:

this.deregister = $rootScope.$on('parent', function listener(){
  someService.addToArray(someData)
})

取消功能需要调用取消注册功能:

  link: function(scope, el) {
    scope.cancel = function(){
      el.remove()
      scope.$destroy()
      scope.vm.deregister()
    }
  },
  controller: 'someController',
  controllerAs: 'vm'
  

在范围被销毁之前不应该取消注册吗?

没关系。正如您所发现的那样,因为侦听器已在$ rootScope上注册,所以它存储在$ rootScope(特别是$rootScope.$$listeners)上的数组中。通过调用取消注册功能将其从$rootScope.$$listeners中删除。

面向对象的运行时(如JavaScript)的本质是,只有当对它们的所有引用都被销毁时,才会从内存中删除对象(垃圾回收)。由于对监听器函数的引用存储在$ rootScope上,因此它(及其执行上下文)仍然存在。

如果侦听器已在指令$ scope上注册,则在范围被销毁时它将自动取消注册。

答案 1 :(得分:0)

我不确定scope.$destroy()是否被正确调用。

正如它在$scope doc中所写的那样:

  

从父级移除当前范围(及其所有子级)   范围。 [...]注意,在AngularJS中,还有一个$ destroy jQuery   event,可用于在元素之前清除DOM绑定   从DOM中移除。

所以,我认为你应该这样做:

link: function(scope, el) {
        el.on('$destroy', function() {
          scope.$destroy();
        });

        scope.cancel = function(){
          el.remove();
        }
      }

告诉我它是否能解决您的问题