Scription
Scription

Reputation: 645

AngularJS - adding directive dynamically to an element

I have created a directive that check if data was entered to an HTML element in the following way:

var myApp = angular.module('myApp', []);

myApp.directive("uiRequired", function () {
return function (scope, elem, attrs) {
    elem.bind("blur", function () {
        var $errorElm = $('#error_testReq');
        $errorElm.empty();
        if (angular.isDefined(attrs) && angular.isDefined(attrs.uiRequired) && attrs.uiRequired == "true" && elem.val() == "") {
            $errorElm.append("<li>Field value is required.</li>");
            $errorElm.toggleClass('nfx-hide', false);
            $errorElm.toggleClass('nfx-block', true);
        }
        else
        {
            $errorElm.toggleClass('nfx-hide', true);
            $errorElm.toggleClass('nfx-block', false);
        }
    });
};

});

A working example can be seen here

My question: Is there a way of adding the directive (uiRequired) I have created dynamically to elements on screen on document ready.

I want to put the new directive on selected HTML elements according to pre-defined list I have. I can not know in advance on which field this directive has to be on.

So I have to put it while page is rendering.

I have tried putting it dynamically myself while page is loading, however AngularJS did interpret it.

I could not find an example on the internet that does that.

Can anyone help me?

Upvotes: 0

Views: 1336

Answers (1)

Michael Kang
Michael Kang

Reputation: 52847

You can dynamically add directives to a page during the compilation phase when Angular is walking the DOM and matching elements to directives. Each step of the compilation process may transform the DOM tree ahead of it, but you should never modify elements that Angular has already compiled. This point is important to remember because adding directives to elements that have already been walked will have no effect. Of course, there ways around this. For example, you could re-compile and re-link previously walked elements. However I strongly advise against this as it may lead to unintended side effects such as memory leaks, and slow performance.

To dynamically add uiRequired directives, you can create a parent directive - let's call it uiRequiredApplier.

app.directive('uiRequiredApplier', function($scope) {
      return {
           restrict: 'A',
           compile: function(element, attr) {
                 // you can apply complex logic figure out which elements
                 // you want to add the uiRequired attribute to
                 $('input', element).attr('uiRequired','');
                 return function(scope, element, attr) {
                 }
           }
      }
});

You can then apply the attribute like this:

<div ui-required-applier>
    <input type="text" ng-model="name" />
</div> 

When the uiRequiredApplier is compiled, it will dynamically add uiRequired attributes to selected elements using jQuery that have not been compiled yet. And when Angular walks the DOM, eventually it will compile and link the uiRequired attributes, which will add the desired validation behavior.

Upvotes: 2

Related Questions