Call function on directive parent scope with directive scope argument

Nick picture Nick · May 5, 2014 · Viewed 41.7k times · Source

I am developing a directive which shows and hides it's contents based on a click event (ng-click) defined in it's template. On some views where the directive is used I'd like to be able to know if the directive is currently showing or hiding it's contents so I can respond to the DOM changes. The directive has isolated scope and I am trying to notify the parent scope when the directive has been "toggled". I'm attempting to accomplish this by passing a callback function to the directive where it is used that can be called when the directive's state changes i.e hides or shows

I'm not sure how to correctly implement this being that the state of the directive (hidden or shown) is stored in the directive's isolated scope and is determined after the ng-click. Therefore I need to call the parent scope's function from within the directive and not from withing the view.

This will make WAAY more sense with an example. Here is a plunked demonstrating what I'd like to do:

http://plnkr.co/edit/hHwwxjssOKiphTSO1VIS?p=info

var app = angular.module('main-module',[])

app.controller('MainController', function($scope){
  $scope.myValue = 'test value';
  $scope.parentToggle = function(value){
    $scope.myValue = value;
  };
});

app.directive('toggle', function(){
    return {
            restrict: 'A',
            template: '<a ng-click="toggle();">Click Me</a>',
            replace: true,
            scope: {
                OnToggle: '&'
            },
            link: function($scope, elem, attrs, controller) {
                $scope.toggleValue = false;
                $scope.toggle = function () {
                    $scope.toggleValue = !$scope.toggleValue;
                    $scope.OnToggle($scope.toggleValue)
                };
            }
        };
});

I'm relatively new to Angular. Is this a bad idea to begin with? Should I be using a service or something rather than passing around function refs?

Thanks!

Answer

Sebastian picture Sebastian · May 5, 2014

Update

You can also use & to bind the function of the root scope (that is actually the purpose of &).

To do so the directive needs to be slightly changed:

app.directive('toggle', function(){
  return {
    restrict: 'A',
    template: '<a ng-click="f()">Click Me</a>',
    replace: true,
    scope: {
      toggle: '&'
    },
    controller: function($scope) {
      $scope.toggleValue = false;
      $scope.f = function() {
        $scope.toggleValue = !$scope.toggleValue;
        $scope.toggle({message: $scope.toggleValue});
      };
    }
  };
});

You can use like this:

<div toggle="parentToggle(message)"></div>

Plunk


You could bind the function using =. In addition ensure the property name in your scope and tag are matching (AngularJS translates CamelCase to dash notation).

Before:

scope: {
  OnToggle: '&'
}

After:

scope: {
  onToggle: '='
}

Furthermore don't use on-toggle="parentToggle({value: toggleValue})" in your main template. You do not want to call the function but just passing a pointer of the function to the directive.

Plunk