should指令调用scope.apply



我正在查看其他人的代码,发现他们的指令中有$scope.$apply

场景是,我们从DOM中获得一些事件,并且我们想要更改范围。

根据我的经验,指令应该调用apply。它会引起一些奇怪的副作用。

其中一个正在指令的测试中。我所有的测试都有相同的模式

$compile( "<the html>" )(scope); 
scope.$digest(); --> will error if directive calls apply
  • 指令调用是否应该应用
  • 当您从DOM中获得未用angular包装的事件时,建议使用什么解决方案来应用范围更改

我会说调用$scope$apply或$scope$摘要通常(尽管并非总是)是个坏主意。
例如,注册DOM事件可以使用ng-click、ng-keydown等进行angular操作,这将隐藏调用$apply或$digest的需要。
之所以需要它,显然是因为有一些代码在angular之外执行,也就是说,在angular生态系统之外,所以angular基本上不"知道"发生了什么事件(或任何其他与数据相关的事情)。
总之,应该有(非常)充分的理由调用$apply或$digest。
否则怎么办?好吧,您可以将这些事件捕获封装在自己的指令中(尽管大多数(如果不是全部的话)都包含在angular中)。这些正是angular本身所做的,并且只有在事件本身实际需要时才会产生$apply或$digest。

/编辑/
例如,angular的ng点击的简化版本可以转换为您自己的指令:

app.directive('myClick', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var clickHandler = $parse(attr.myClick);
            element.on('click', function(event) {
                // Do some of your own logic if needed.
                scope.$apply(function() {
                    // Calling the event handler.
                    clickHandler(scope, {$event: event});
                });
            });
        }
    }
}]);  

通过封装这个事件处理程序,它可以被重用(在这种情况下是一种指令的形式),而且由于它是angular世界的一部分,任何使用这个指令的其他逻辑都不必担心$apply或$digest。这也意味着它现在可以声明性地使用(而不是操作性地),这正是angular所渴望的。

需要注意的一点是,该指令没有隔离的作用域,也没有在作用域上引入任何其他新变量(事件处理程序正在链接函数上解析)。这一点很重要,因为这意味着父作用域(需要"了解"此事件的作用域,基本上是主作用域)没有开销副作用,因为指令的作用域是继承的。

p.S您也可以考虑在angular上重写指令或装饰其他服务。

嗯。。。如果您的指令包装了一些本机事件或Angular范围之外的任何东西,那么除了调用"$apply()"之外,您没有更多的选择了。根据我的经验,如果同时从角度范围内和外部调用此函数,这只会导致错误(例如,点击以及窗口点击事件或其他事件)。如果是这种情况,您仍然可以使用$timeout服务。这不是最好的解决方案,但据我所知,甚至是棱角分明的团队提出的解决方案。

最新更新