在指令中调用$ compile($ element)($ scope)的目的是什么?

时间:2015-01-15 23:18:40

标签: javascript angularjs dom

角度代码placed on jsfiddle与自定义指令有关,该指令使用$compile($element)($scope)并导致ng-click操作发生两次: 我的问题是:

  • 我想了解,为什么ng-click动作正在发生 两次?
  • 致电$compile($element)($scope)的目的是什么?
  • 如果没有被调用会发生什么,在什么情况下应该这样 被称为?

以下是我到目前为止收集的详细信息:

我想了解,为什么ng-click操作会发生两次?以下行显示了自定义指令" hello"并点击按钮。自定义指令调用$compile($element)($scope),这就是导致操作被触发两次的行,但我不明白怎么做?

测试点击!

以下是代码 - http://jsfiddle.net/4x4L3gtw/27/

<div ng-app='myApp' ng-controller='DirectiveTestController'>
    <button hello ng-click="testClick()">Test CLICK!</button>
</div>

var myApp = angular.module('myApp', []);
myApp.controller('DirectiveTestController', ['$scope',

function ($scope) {
    $scope.testClick = function () {
        window.alert("hey");
        console.log("hey");
    }
}]);
myApp.directive('hello', function () {
    return {
        scope: true,
        controller: ['$scope', '$element', '$compile', function ($scope, $element, $compile) {
            $element.removeAttr('hello');
            //          $element.removeAttr('ng-click');
            $compile($element)($scope);
        }]

    };
});

调用$compile($element)($scope)的目的是什么,如果没有调用它会发生什么?在什么情况下应该调用它?

(点击按钮,你会发现动作发生了两次)

该指令的目的是基于某些逻辑隐藏/禁用。 所以在这个指令中,我看到$element.removeAttr("ng-hide")等,每次调用$element.removeAttr时都跟着$compile($element)($scope),重写DOM的目的是什么?

我检查了DOM,但我没有看到多次定义的ng-click。在检查DOM(firebug)时,我查看了$ element-&gt; 0-&gt; attributes-&gt; ng-click(以及其他元素)。

如果我使用$element.removeAttr("ng-click")删除ng-click,则该操作仅发生一次。 或者,如果我删除$compile($element)($scope),则只会执行一次操作。

3 个答案:

答案 0 :(得分:3)

我认为发生这种情况的主要原因是因为您在应用指令的元素中使用了click事件,而不是直接在指令中定义此事件。因此,您将从按钮元素中获取单击,但也可以从指令控制器中单击。

$ compiles做的是一旦针对标记调用将生成一个函数,您可以使用该函数将标记绑定到特定范围(Angular调用链接函数),这就是Rodion建议使用链接的原因,我想。在这种特殊情况下,它意味着您正在元素按钮中直接使用事件,然后使用$ compile将其再次链接到指令中的范围。我猜这就是为什么你得到两次消息。

由于我不知道这是否清楚,我从这个链接http://odetocode.com/blogs/scott/archive/2014/05/07/using-compile-in-angular.aspx获得了更好解释的信息。

这里还有一个JSFiddle,你可以看到它是如何工作的(摘自上面的文章)。

app.directive("otcDynamic", function($compile){
   return {
        link: function(scope, element){
            var template = "<button ng-click='doSomething()'>{{label}}</button>";
            var content = $compile(template)(scope);
            element.append(content);
        }
    };
});

JSFiddle

答案 1 :(得分:0)

我认为这样的操作(使用html)应该在链接中(不在控制器中):

link: function (scope, element) { element.removeAttr('hello'); }

http://jsfiddle.net/4x4L3gtw/32/

答案 2 :(得分:0)

编译 - $ compileProvider - 模块化服务 将HTML字符串或DOM编译为模板并生成模板函数,然后可以将其用于将范围和模板链接在一起。

编译是一个遍历DOM树并将DOM元素与指令匹配的过程。