2

I have 2 AngularJS Directives which are very similar, so i want to use one single controller to handle both of them. In order to differentiate in the Controller code between the 2 directives, I want to be able to know which directive is currently being used. Is there a way i can tell? it sounds like a trivial function in AngularJS, but i can't find it in the docs so far.

<div dirA ></div>
<div dirB'></div>

app.directive('dirA', function() {
    return {
        restrict: 'A',
        replace: true,
        controller: 'CommonCtrl',
    };
});

app.directive('dirB', function() {
    return {
        restrict: 'A',
        replace: true,
        controller: 'CommonCtrl',
    };
});

app.controller('CommonCtrl',
    function CommonCtrl($scope, $location, $log, $attrs) {
      // how do i know which directive is using me now???
    }
);
7
  • If you need to know which directive is using it, can you really say that the controller is common between the two? Commented Oct 7, 2013 at 16:49
  • I was going to ask the same :) Commented Oct 7, 2013 at 16:50
  • write two controllers and isolate their common functionality into a function. Commented Oct 7, 2013 at 16:51
  • I've added an answer that will work for you, but I think the suggestion at the end of my answer is probably your best bet. I can add some code to show that if you like. Commented Oct 7, 2013 at 19:29
  • @Fourth the language probably failed me here :) there is very little deviation in functionality between DirA and DirB. When i said common, i meant there is common functionality between the 2 and i need to branch the logic in some statements based on the directive name, or if you can help with a better practice in AngularJS? Commented Oct 7, 2013 at 19:47

1 Answer 1

2

Sure you can just set a property on the directive's controller, which is automatically injected to your linking function if specified:

Here's a plunk for it

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

app.directive('dirA', function (){
  return {
    controller: 'CommonCtrl',
    scope: true,
    template: '<button ng-click="test()">Test A</button>',
    link: function(scope, elem, attrs, ctrl) {
      ctrl.directiveName = 'dirA';
    }
  };
});

app.directive('dirB', function (){
  return {
    controller: 'CommonCtrl',
    scope: true,
    template: '<button ng-click="test()">Test B</button>',
    link: function(scope, elem, attrs, ctrl) {
      ctrl.directiveName = 'dirB';
    }
  };
});

app.controller('CommonCtrl', function ($scope, $window){
  var ctrl = this;
  
  $scope.foo = 'bar';
  
  $scope.test = function (){
    $window.alert('Directive name is: ' + ctrl.directiveName);
  };
});

This is probably not a good idea, though.

Coupling Warning!

This is going to lead to slightly tighter coupling in your app. Because now you have a dependency between your Controller which is supposed to encapsulate logic that manipulates your $scope (model), and your View because now your controller has a reference to a directive name or directive-specific data at least. This is going to hurt testability and possibly readability in the long run.

Suggestion: Use Inheritence

If the case is that you have slightly different functionality from different directives, it's probably better practice to create a CommonCtrl, then create a DirACtrl and DirBCtrl that prototypically inherit from CommonCtrl... if that makes sense.

Sign up to request clarification or add additional context in comments.

1 Comment

thanks for the answer, i was using something similar already putting the directive as an attribute, so i can check for $attrs.dirA exists.I thought there is an easier way to do it natively. As for inheritance suggestion, i will try that again, but i didn't feel that i can separate the common code without duplicating the whole function, this is why i was looking for easier way to branch from a couple of statements in the code. i wish to vote up this answer, but this is my first question and apparently i still need more reputation to vote up, which i will get and i appreciate your help :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.