dnc253
dnc253

Reputation: 40337

How to handle competing directives from different modules

I have 2 attribute directives (restrict is set to 'A' on both), dir1 and dir2 that are defined in two different modules. In one app (that includes both these modules), we have an element where one of these 2 directives could get added. We currently set things up so that dir1 is the default for this element, but we want a way to have dir2 "override" this directive.

The element we want to do this with is part the template of another directive, parentDir, so my first thought was adding some functionality to the compile function for parentDir. The template for parentDir would have in it <div class="myElement" dir1="{{data}}"></div> and then the compile function would look something like this:

function(tElement, tAttrs) {
    if ("true" == tAttrs.useDir2)
    {
        var myElement = tElement.find("div.myElement");
        myElement.removeAttr("dir1");
        myElement.attr("dir2", "{{data}}");
    }

    return function (scope, element, attrs) {
    // link stuff
    }
}

where useDir2 would be an attribute on the parentDir directive. This would work fine, but the value for useDir2 is an interpolated value, so I wouldn't be looking at the value I want with tAttrs.useDir2.

I thought about setting priorities on the 2 directives, but then each directive would have to know the other's priority to make sure they related to each other correctly. You wouldn't want someone to come into one module and change the priority for something else, and break this functionality. Since the two directives are in different modules, I want them to be completely ignorant of each other.

I hope I've explained my problem clearly enough. I'm just not sure how to go about doing this, and think I may be missing some easy way to do this. Thanks.

Upvotes: 1

Views: 139

Answers (1)

Caio Cunha
Caio Cunha

Reputation: 23394

I believe you will need to do something like you proposed. If you need it to be defined in run-time (i.e. by the controller), in your linking function, $observe the attribute and then change and recompile the element contents when the value is changed. Something like this:

app.directive('parentDir', function($compile) {
  return {
    link: function(scope, element, attr) {
        attr.$observe('parentDir', function(value) {
            var div = angular.element('<div ' + value + '></div>');
            element.find('div').remove();
            element.append(div);
            $compile(div)(scope);
        });
    },
    template: '<input type="checkbox" ng-model="val"/> Use directive 2: ' + 
            '<div></div>'
  };
});

I made a fiddle.

Naturally, I simplified the parentDir, you might need to cache the original state of the DOM, so you can safely recompile it.

Upvotes: 1

Related Questions