Jeanluca Scaljeri
Jeanluca Scaljeri

Reputation: 29159

Angular: Bind function from child to parent

Normally we give a child-directive a callback function which it can call if something happens. In my case, its the other way around; I would like to inform the directive about something. I'm still using angular 1.4 (but soon I'll move to 1.5 and eventually to 2). With this in mind I would like to avoid things like $watch and $broadcast.

So, I think there are two solution: 1) use a service and 2) bind a callback function from the child to the parent

1) Although this might be the preferred solution I see two problems a) A whole service for such a simple task b) you'll need $watch to detect the change

2) Well, this solution sounds super easy, but it seems to be more complicated than I expected or maybe it is not even possible :(

Here is my test code:

<button ng-click="mycontroller.callback()">Click me</button> 
<bar-foo activate-me="mycontroller.callback"></bar-foo>

So, mycontroller doesn't have a function callback, but the directive bar-foo does

angular.module('HelloApp')
    .directive('barFoo', function () {
        return {
            restrict: 'E',
            scope:{
                activateMe: '='
            },
            controller: function ($scope) {
                $scope.activateMe = function () {
                    this.activated = true
                }
            },
            template: '<p ng-if="activated">Activated</p>'
        }
    });

DEMO

Is what I'm trying possible ? or should I accept that services are the one and only way to tackle this or is there more ?

Upvotes: 1

Views: 1202

Answers (2)

dfsq
dfsq

Reputation: 193291

I think you are thinking too hard here. While it is possible to give outer controller a function to call and notify directive directly (which you should not do), much more straightforward and and natural approach is to use input binding. In your case it will be as simple as:

angular.module('HelloApp', []).controller("MyCtrl", function($scope) {
  this.callBarFoo = function() {
    this.callback = true;
  }
});

angular.module('HelloApp')
  .directive('barFoo', function() {
    return {
      restrict: 'E',
      scope: {
        activateMe: '='
      },
      controller: function($scope) {

      },
      template: '<p ng-if="activateMe">Activated</p>'
    }
  })
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>

<div ng-app="HelloApp" data-ng-controller="MyCtrl as mycontroller">
  <button ng-click="mycontroller.callBarFoo()">Click me</button>
  
  <bar-foo activate-me="mycontroller.callback"></bar-foo>
</div>

In general, controller is supposed to let directive know about data whenever it is appropriate. This is recommended data flow direction: from controller -> into directive. Directive should never ask for data itself. It's controller who decides when and what to pass into directive. When directive might need some data - then two-way binding can be used.

Related reading I put together here.

Upvotes: 1

Ashot
Ashot

Reputation: 1300

The one alternative way I know it is to attach some id to directive root element . Then from your controller you can do so .

angular.element(document.getElementById('the-id')).scope().directiveFunction(args);

Upvotes: 0

Related Questions