Angularjs directives for beginners. Part 1

  • Tutorial
In my opinion, directives are the main highlight of Angularjs declarative style. However, if you open user comments in the section of official documentation of Angularjs devoted to directives , you will see that the most popular of them: “Please rewrite the documentation, make it more accessible and structured. It’s hard for a novice Angularjs developer to figure it out ”(“ Please rewrite a clearer well structured documentation of directives., This is not friendly to first time angular developers ”). It’s difficult to disagree with this, the documentation is still damp and in some moments it is necessary to make great efforts to understand the logic and essence of the functional. Therefore, I offer you my free retelling of this chapter in the hope that this will save someone time, and I also count on your support and participation in the comments. So let's go!

How to write directives?


Angularjs directives are set along with other module configurations as follows:

angular.module('moduleName', [])
    .directive('directiveName', function () {
        /*Метод-фабрика для директивы*/
    })
    .directive('anotherDirectiveName', function () {
        /*Метод-фабрика для директивы*/
    });

There are two options for their announcement. Simpler and more powerful long options.

A simple way to create a directive


In order to write a directive that will be called when specifying in HTML markup, in the simplest case you need to set some function (it is called Linking Linking , but more on that later) returned by the factory:

angular.module('moduleName', [])
    .directive('directiveName', function () {
        return function(scope,element,attrs){
        }
    });

This function takes the following parameters:
  • scope - the scope in which the directive is called
  • element - the DOM element that owns the directive wrapped in jQuery Lite
  • attrs - an object with a list of all attributes of the tag in which the directive is called

Let's use a more detailed example. We write such a directive (let's call habra-habr ), which will fold two lines and display inside the layout element in which it is called. At the same time, we will set one line as the controller variable ( forExampleController ), and the second to pass the attribute ( habra ) in the same tag. And also reserve the ability to determine the name of the controller variable when calling the directive:

[ jsFiddle ]

function forExampleController($scope) {
    $scope.word="Habrahabra"
}
angular.module('helloHabrahabr', [])
  .directive('habraHabr', function() {
    return function($scope, element, attrs) {
        /*Задаем функцию, которая будет вызываться при изменении переменной word, ее имя находится в attrs.habraHabr*/
        $scope.$watch(attrs.habraHabr,function(value){
            element.text(value+attrs.habra);
        });
    }
  });

All. The directive in our primitive form is ready. You can move on to a more detailed form.

Expanded Option


In its full form, the task of the directive is as follows:

angular.module('moduleName', [])
    .directive('directiveName', function () {
        return {
             compile: function compile(temaplateElement, templateAttrs) {
                return {
                    pre: function (scope, element, attrs) {
                    },
                    post: function(scope, element, attrs) { 
                    }
                }
            },
            link: function (scope, element, attrs) {
            },
            priority: 0,
            terminal:false,
            template: '
', templateUrl: 'template.html', replace: false, transclude: false, restrict: 'A', scope: false, controller: function ($scope, $element, $attrs, $transclude, otherInjectables) { } } });

All these properties are quite closely related and intertwined. And in order to make it easier to understand this, it is better to consider them with certain semantic groups.

Link and Compile

The Link method is the very function that the directive factory returned in the short version. Here you need to understand that in Angularjs the compilation process is divided into two stages:

  • compile - analysis of all directives used in this DOM element (including its child descendants )
  • linking - linking variables used in the template and variables in scope


And at the same time, both in the simplest version and in the extended method, Link will correctly call postLink , since it is executed after the variables are already mapped. Let's look at some examples.

First, I suggest rewriting an example of a simple directive in the manner of an extended one.

[ jsFiddle ]
angular.module('helloHabrahabr', [])
    .directive('habraHabr', function() {
        return {
            link:function($scope, element, attrs) {
                /*Задаем функцию, которая будет вызываться при изменении переменной word*/
                $scope.$watch(attrs.habraHabr,function(value){
                        element.text(value+attrs.habra);
                    }
                );
            }
        }
    });

That is, everything really works as before. Now we can complicate the task and make our phrase displayed not through direct interaction with the DOM element.text (...) , but inside the interpolate "{{}}" directive :

[ jsFiddle ]
angular.module('helloHabrahabr', [])
    .directive('habraHabrNotwork', function() {
        return {
            link:function($scope, element, attrs) {
               element.html("
{{"+attrs.habraHabrWork+"}}"+attrs.habra+"
"); } } }) .directive('habraHabrWork', function() { return { compile: function compile(templateElement, templateAttrs) { templateElement.html("
{{"+templateAttrs.habraHabrWork+"}}"+templateAttrs.habra+"
"); }, link: function (scope, element, attrs) { } } });

The example is updated after the tamtakoe comment .

In the example above, the habraHabrNotwork directive will not work correctly, since we insert the directive "{{}}" with variables in postLink, that is, when compilation and linking are already completed. In other words, Angularjs doesn't even know that "{{}}" is a directive that must be enforced.

Another thing, the second directive. Everything is in its place, we insert the template "{{" + attrs.habraHabrNotwork + "+" + attrs.habra + "}}" before compilation, and it successfully passes the rendering.

Let's dwell on the compile method. It can return both a postLink function and an object with two parameters: pre and post. Where pre and post are the preLink and postLink methods, respectively. From the name of the methods it may seem that we are talking about the methods before and after Link a. But this is not entirely true, these functions are performed before and after Link and the children directives in the DOM. For example:

[ jsFiddle ]
{{log}}


function forExampleController($scope) {
    $scope.word="Habrahabra";
    $scope.log="";
}
angular.module('helloHabrahabr', [])
    .directive('habraHabrWork', function() {        
        return {
            compile: function compile(templateElement, templateAttrs) {
                templateElement.prepend("
{{"+templateAttrs.habraHabrWork+"}}"+templateAttrs.habra+"
"); return { pre: function ($scope, element, attrs, controller) { $scope.log+=templateAttrs.habra +' preLink \n'; }, post: function ($scope, element, attrs, controller) { $scope.log+=templateAttrs.habra +' postLink \n'; } } } } });


On this I propose to pause. If the topic is interesting, in the coming days I will try to write a continuation about the scope and templates.

Also popular now: