Calling a parent directive function in a child directive

Hey. I'm trying to create a system pane where elem.bind ('change, ...) in the child directive changes the "selected" parent directive: http://plnkr.co/edit/gc35fuUiJVUhHF4QMAwv?p=preview

(function(angular) {
  'use strict';
  angular.module('docsTabsExample', [])
    .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;
          };
          $scope.next = function(pane) {
            select(panes[panes.indexOf(pane)+1]);
          };
          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'
      };
    })
    .directive('pf-data', function() {
      return {
        require: '^myPane',
        restrict: 'AEC',
        scope: {
          title: '@'
        },
        link: function(scope, element, attrs, tabsCtrl) {
          console.log("hi");
          element.bind('change', function() {
            scope.next();
            console.log("switch panes");
          });
        }
      };
    });
})(window.angular);

      

(When you select gender (male or female), I want it to go to the next pane sequentially, but I'm guessing due to scope issues (I'm pretty rusty with angular) that it never gets into the associated attribute of the child directive.

Any ideas?

+3


source to share


2 answers


Each of your directives defines an isolated scope (it's pretty much empty except for the content of the scope

directive's definition element . So when you say scope.next()

it will fail unless it is in that collection or explicitly bound by a function link

, so use $scope

to access your parenting won't work, and you certainly don't want the leaked internal data to be passed through attributes. That should break the gist of these related directives.

But you have something even better.

Since you use require

to chain your directives together, you don't even need to worry about these games. Within, pf-data

you define:

require: ['^myPane', '^myTabs]

      

This will give you direct access to both controllers. You need to expose next

in the directive myTabs

. To be honest, I would find a way to use indices rather than looping through all of your panels by setting true and false. Something like:

var currentPane;
this.next = function() {
  select(nextPane(currentPane));
};

      

And now, in the pf data, you have access through your function link

:



link: function(scope, element, attrs, ctrls) {
      element.bind('change', function() {
        $scope.$apply(function() {
          ctrls[1].next();
          scope.next();
        };
      });
  ...

      

Update

I unlocked the new Plnkr from the one you provided to include the changes we talked about. I also dropped the request myPane

from pf-data

(which would still fail because of transclude

).

http://plnkr.co/edit/LP0RYu6AKxeKyhHY5rZP?p=preview

Updates include:

  • pf-data

    was changed to pfData

    - this is just one of these angular rules. Your directives are named with camel case but end like a hyphen in your html.
  • I have implemented all the little things that I talked about. scope.$apply

    and changing require

    to use myTabs

    . As we discussed in the comments, you need to use $apply

    whenever you are capturing events that are not directly part of angular in order to signal updates to the elements on the screen.
  • I am throwing all your methods into myTabs

    on this

    instead of $scope

    . You will need them there, since you are going to them through the controller mechanism.
  • I keep the selected panel in the controller so we can just tell next()

    without supplying the panel.
+4


source


You are correct - this is an area problem. When you use isolated scope, the only scope variables that are available in your scoped directives from the parent scope are the ones you pass through attributes. To call next (), which is defined in the parent scope inside your directive, pass the method through the attribute with '&' binding:

  scope: {
       title:'@',
       next: '&'
  }

      



HTML:

 <my-pane next="next()"></my-pane>

      

+2


source







All Articles