Tuesday, June 17, 2014

Angular Directives Part 7 - Angular directive shows $comple

Shows how to repeat elements

Very simple directive that will repeat a particular element a given number of times:

<div repeat-x="5">Hello</div>

// Directive to repeat an element x number of times
angular.module('app').directive('repeatX', [function () {
    return {
        link: function (scope, element, attrs, controller) { // The link function gets called for every instance of this directive.
            for (var i = 0; i < Number(attrs.repeatX) - 1; i  ) {
                // When we clone the element, we need to modify the attribute because it has repeat-x attribute.
                // We modify the attribute of the cloned element so that they repeat zero times.
                element.after(element.clone().attr('repeat-x', 0));
            }
        }
    };
}]);
But if you try to add binding, it's not going to work. The solution is to use the compile service:
    Text to repeat: <input type="text" ng-model="text" />
    <div repeat-x="5">{{text}}</div>

JavaScript

// Directive to repeat an element x number of times
angular.module('app').directive('repeatX', ['$compile', function ($compile) {
    return {
        link: function (scope, element, attrs, controller) { // The link function gets called for every instance of this directive.
            for (var i = 0; i < Number(attrs.repeatX) - 1; i  ) {
                // When we clone the element, we need to modify the attribute because it has repeat-x attribute.
                // We modify the attribute of the cloned element so that they repeat zero times.
                element.after($compile(element.clone().attr('repeat-x', 0))(scope));
            }
        }
    };
}]);
The $compile service is pretty expensive. The alternative is to use the compiler function:

JavaScript

// Directive to repeat an element x number of times
angular.module('app').directive('repeatX', [function () {
    return {
        // The compile function is used to manipulate the dom prior to the link function executing
        // Note that unlike the link function, there's no scope or controller being passed in.
        // compile function runs once and affects all instances of the directive the same way.
        // The link function runs individually for each instance / usage of the directive in the HTML.
        compile: function (element, attrs) {
            for (var i = 0; i < Number(attrs.repeatX) - 1; i  ) {
                // When we clone the element, we need to modify the attribute because it has repeat-x attribute.
                // We modify the attribute of the cloned element so that they repeat zero times.
                element.after(element.clone().attr('repeat-x', 0));
            }
        }
    };
}]);
The compile function can return a link function. Let's change the html and give a text attribute:
    Text to repeat: <input type="text" ng-model="text" />
    <div repeat-x="5" text="{{text}}">{{text}}</div>
Now observe the text attribute and when it changes to "Hello World", make it red.
// Directive to repeat an element x number of times
angular.module('app').directive('repeatX', [function () {
    return {
        // The compile function is used to manipulate the dom prior to the link function executing
        // Note that unlike the link function, there's no scope or controller being passed in.
        // compile function runs once and affects all instances of the directive the same way.
        // The link function runs individually for each instance / usage of the directive in the HTML.
        compile: function(element, attrs) {
            for (var i = 0; i < Number(attrs.repeatX) - 1; i++) {
                // When we clone the element, we need to modify the attribute because it has repeat-x attribute.
                // We modify the attribute of the cloned element so that they repeat zero times.
                element.after(element.clone().attr('repeat-x', 0));
            }

            // Optionally return a link function, which will be executed for each element.
            return function (scope, element, attrs, controller) {
                attrs.$observe('text', function(newValue) {
                    if (newValue === 'Hello World') {
                        element.css('color', 'red');
                    }
                });
            };
        }
    };
}]);

No comments: