0

I have an attribute directive and I'd like to expose an API on that directive to be called on the controller.

I followed the top answer from this question but this no longer seems to work anymore, or at least it doesn't work for me. Since it's been almost three years, how can I do this now?

In my "myDirective" directive I have:

return {
        restrict: 'A',
        scope: { 
            api: '='
        },
        link: function(scope, element){
        scope.api = { 
                someFunction: function(){...}
        }
        ...
}

In my markup I have:

<div myDirective api="b"></div>

And finally in my controller, I try to call:

$scope.b.someFunction() --> undefined is not an object
Community
  • 1
  • 1
PDN
  • 771
  • 2
  • 13
  • 29
  • Create a service for the directive which you hook to the directive and controller. – Chrillewoodz Apr 06 '16 at 05:59
  • 1
    What are you trying to achieve exactly? Directives aren't supposed to expose an API for controllers. That's what services do. – JB Nizet Apr 06 '16 at 06:00
  • @JBNizet so, in my directive, I'm adding event handlers to an element. To remove the event handlers, I need references to the handler functions. Are you suggesting I define the handlers in a service instead, and call the service to both add and remove the handlers? – PDN Apr 06 '16 at 06:01
  • No, not at all. The directive should instead do that by itself, by listening to the $destroy event, and remove its event listeners at this time (if needed: most of the time, when the directive is destroyed, the elements with the added listeners are destroyed too). – JB Nizet Apr 06 '16 at 06:06
  • @JBNizet In my case, I need to remove the handlers dynamically. In other words the elements I'm trying to remove the handlers from will still be present, so I can't listen to the $destroy event. How can I accomplish that? – PDN Apr 06 '16 at 06:07
  • By having your directive take some flag as attribute, watch the value of that flag, and act accordingly, for example. Or by listening to scope events that would be broadcasted by the controller. Or by sharing a service with the controller: the controller would call a service method, that would change some state, and would cause the directive to know what to do. – JB Nizet Apr 06 '16 at 06:10
  • @JBNizet thank you so much! I think I'm getting the hang of this angular thing :P – PDN Apr 06 '16 at 06:11
  • That said, your code should work, provided that you use `my-directive` instead of `myDirective` in the view, and that you don't call the b function too soon in the controller (i.e. before the directive has been instantiated and has added b to the scope). What you're doing is basically what the form directive does. But in most cases, it's not a good idea. – JB Nizet Apr 06 '16 at 06:17

1 Answers1

0

The way to do so, is to create a service that is used as an API for both the directive and the controller.

Inject the service into your directive controller to use it in the directive, and inject it into the controller.

All the API logic should be in the service, so calling the functions from either the directive or the controller will have the same result.

Ron Dadon
  • 2,666
  • 1
  • 13
  • 27