Duane Haworth
Duane Haworth

Reputation: 79

Sharing two AngularJS directives with a third

EDIT Here is my plunk

Here are the two lines in the myPane directive that causes it to break.

require: '^myMainTabs',  //Comment out this line and uncomment below to break.
//require: ['^myMainTabs', '^mySubTabs'],  //Comment out this line and uncomment above to fix.

I'd like to be able to use the same 'myPane' directive for both of these tabs, if that's possible.

End EDIT

I'm looking at the AngularJs Developer Guid at this site. At the bottom I found something I'd like to use for the base for tabs.

Here is the code found at that page.

.directive('myTabs', function() {
  return {
    restrict: 'E',
    transclude: true,
    scope: {},
    controller: function($scope) {
      var panes = $scope.panes = [];

      $scope.select = function(pane) {
        angular.forEach(panes, function(pane) {
          pane.selected = false;
        });
        pane.selected = true;
      };

      this.addPane = function(pane) {
        if (panes.length === 0) {
          $scope.select(pane);
        }
        panes.push(pane);
      };
    },
    templateUrl: 'my-tabs.html'
  };
})
.directive('myPane', function() {
  return {
    require: '^myTabs',
    restrict: 'E',
    transclude: true,
    scope: {
      title: '@'
    },
    link: function(scope, element, attrs, tabsCtrl) {
      tabsCtrl.addPane(scope);
    },
    templateUrl: 'my-pane.html'
  };
});

What I've done is applied my company's theme to this and now it looks like tabs and works great!

However, we have two or three different tab types, but in the end, they could all use the same 'myPane' directive. I tried changing the require in the myPane directive to an array of directives, such as:

require: ['^tabType1', '^tabType2']

but that seems to require both types of directives to be required.

Is there a way for a directive to be shared by other directives?

Something like this:

.directive('myMainTabs', function() {
  return {
    restrict: 'E',
    transclude: true,
    scope: {},
    controller: function($scope) {
      var panes = $scope.panes = [];

      $scope.select = function(pane) {
        angular.forEach(panes, function(pane) {
          pane.selected = false;
        });
        pane.selected = true;
      };

      this.addPane = function(pane) {
        if (panes.length === 0) {
          $scope.select(pane);
        }
        panes.push(pane);
      };
    },
    templateUrl: 'my-main-tabs.html'
  };
})
.directive('mySubTabs', function() {
  return {
    restrict: 'E',
    transclude: true,
    scope: {},
    controller: function($scope) {
      var panes = $scope.panes = [];

      $scope.select = function(pane) {
        angular.forEach(panes, function(pane) {
          pane.selected = false;
        });
        pane.selected = true;
      };

      this.addPane = function(pane) {
        if (panes.length === 0) {
          $scope.select(pane);
        }
        panes.push(pane);
      };
    },
    templateUrl: 'my-sub-tabs.html'
  };
})
.directive('myPane', function() {
  return {
    require: ['^myMainTabs','^mySubTabs'] //Doesn't work
    restrict: 'E',
    transclude: true,
    scope: {
      title: '@'
    },
    link: function(scope, element, attrs, tabsCtrl) {
      tabsCtrl.addPane(scope);
    },
    templateUrl: 'my-pane.html'
  };
});

Thanks, Duane

Upvotes: 0

Views: 99

Answers (2)

gkalpak
gkalpak

Reputation: 48212

Since only one of the two parent directive's (and thus controllers) will be available at a time, you could make them optional (using ?) and check which one is present:

require: ['^?myMainTabs', '^?mySubTabs'],
...
link: function (scope, elem, attrs, ctrls) {
    var tabsCtrl = ctrls[0] || ctrls[1] || null;
    if (!tabsCtrl) return;

    tabsCtrl.addPane(scope);
}

See, also, this short demo.

Upvotes: 1

Michael Kang
Michael Kang

Reputation: 52847

Since you have an array of controllers in your 'require' attribute within your myPane directive, then tabsCtrl will be an array of controllers. You can access it as you would access a normal array:

tabsCtrl[0] --> first controller (myMainTabs)
tabsCtrl[1] --> second controller (mySubTabs)

Upvotes: 0

Related Questions