Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of calling $compile($element)($scope) in a directive

The angular code placed on jsfiddle is regarding a custom directive, that uses $compile($element)($scope) and causes the ng-click action to happen twice: My questions are:

  • I would like to understand, why is the ng-click action happening twice?
  • What is the purpose of calling $compile($element)($scope)?
  • what happens if it is not called, under what circumstances should it be called?

Here are the details and what I have gathered so far:

I would like to understand, why is the ng-click action happening twice? The following line shows the custom directive "hello" and ng-click on a button. The custom directive calls $compile($element)($scope) and that is the line that causes the action being fired twice, but I don't understand how?

Test CLICK!

Here is the code - 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);
        }]

    };
});

What is the purpose of calling $compile($element)($scope), what happens if it is not called and under what circumstances should it be called?

(click on the button and you will notice that the action happens twice)

The intent of the directive is to hide/disable based on some logic. so in this directive I see $element.removeAttr("ng-hide"), etc, and each time the $element.removeAttr is called it is followed with a $compile($element)($scope), is the purpose to re-write the DOM?

I examined the DOM and I don't see ng-click defined multiple times. When examining the DOM (firebug), I looked at $element->0->attributes->ng-click (among other elements).

If I remove ng-click using $element.removeAttr("ng-click") then the action only happens once. Or if I remove the $compile($element)($scope) the action only happens once.

like image 613
liontale Avatar asked Jan 15 '15 23:01

liontale


People also ask

What is$ compile AngularJS?

Compiler is an AngularJS service which traverses the DOM looking for attributes. The compilation process happens in two phases. Compile: traverse the DOM and collect all of the directives. The result is a linking function. Link: combine the directives with a scope and produce a live view.

What is compile directive?

A compiler directive is a statement that causes the compiler to take a specific action during compilation. Conditional compilation. Conditional compilation provides a way of including or omitting selected lines of source code depending on the values of literals specified by the DEFINE directive.

How AngularJS is compiled?

AngularJS compilation process takes place in the Web Browser. No Server side or pre-compilation step is involved. Angular uses $compiler service to compile your Angular HTML page. The Angular compilation process begins after your HTML page (static DOM) is fully loaded.


1 Answers

I think the main reason why this is happening is because you are using a click event in the element where you apply the directive, instead of defining this event directly in the directive. Therefore you are getting the click from the button element, but also the click from the directive controller.

What $compiles do is once invoked against markup will produce a function you can use to bind the markup against a particular scope (what Angular calls a linking function), that's why Rodion suggested using link, I guess. In this particular case, it means that you are are using an event directly in the element button but then linking it again to the scope in your directive by using $compile. I guess that's why you get the message twice.

As I don't know whether this is clear, I obtained the information from this link http://odetocode.com/blogs/scott/archive/2014/05/07/using-compile-in-angular.aspx where it is way better explained.

Here also a JSFiddle where you can see how it works (excerpt from the article above).

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

like image 139
Gonzalo Avatar answered Oct 19 '22 18:10

Gonzalo