Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access controller scope from directive

Tags:

I've created a simple directive that displays sort column headers for a <table> I'm creating.

ngGrid.directive("sortColumn", function() {     return {         restrict: "E",         replace: true,         transclude: true,         scope: {             sortby: "@",             onsort: "="         },         template: "<span><a href='#' ng-click='sort()' ng-transclude></a></span>",         link: function(scope, element, attrs) {             scope.sort = function () {                  // I want to call CONTROLLER.onSort here, but how do I access the controller scope?...                 scope.controllerOnSort(scope.sortby);             };         }     }; }); 

Here's an example of some table headers being created:

<table id="mainGrid" ng-controller="GridCtrl> <thead>     <tr>         <th><sort-column sortby="Name">Name</sort-column></th>         <th><sort-column sortby="DateCreated">Date Created</sort-column></th>         <th>Hi</th>     </tr> </thead> 

So when the sort column is clicked I want to fire the onControllerSort function on my grid controller.. but I'm stuck! So far the only way I've been able to do this is for each <sort-column>, add attributes for the "onSort" and reference those in the directive:

<sort-column onSort="controllerOnSort" sortby="Name">Name</sort-column> 

But that's not very nice since I ALWAYS want to call controllerOnSort, so plumbing it in for every directive is a bit ugly. How can I do this within the directive without requiring unnecesary markup in my HTML? Both the directive and controller are defined within the same module if that helps.

like image 712
Matt Roberts Avatar asked Oct 15 '13 15:10

Matt Roberts


People also ask

How is scope in directive different from scope in controller?

By default, directives do not create their own scope; instead they use the scope of their parent, generally a controller (within the scope of which the directive is defined). We can change the default scope of the directive using the scope field of the DDO (Data Definition Object).

How do you access the directive variable in a controller?

You just create a myVar variable in your controller and pass it to the directive using my-var attribute. Since you are using two way binding, any changes made to myVar by the directive are available in your controller.

What type of scope allows a directive to be used within a given scope?

Directives that Create Scopes A special type of scope is the isolate scope, which does not inherit prototypically from the parent scope. This type of scope is useful for component directives that should be isolated from their parent scope.

What is scope in custom directive?

In an AngularJS directive the scope allows you to access the data in the attributes of the element to which the directive is applied. This is illustrated best with an example: <div my-customer name="Customer XYZ"></div> and the directive definition: angular. module('myModule', []) .


2 Answers

Create a second directive as a wrapper:

ngGrid.directive("columnwrapper", function() {   return {     restrict: "E",     scope: {       onsort: '='     }   }; }); 

Then you can just reference the function to call once in the outer directive:

<columnwrapper onsort="controllerOnSort">   <sort-column sortby="Name">Name</sort-column>   <sort-column sortby="DateCreated">Date Created</sort-column> </columnwrapper> 

In the "sortColumn" directive you can then call that referenced function by calling

scope.$parent.onsort(); 

See this fiddle for a working example: http://jsfiddle.net/wZrjQ/1/

Of course if you don't care about having hardcoded dependencies, you could also stay with one directive and just call the function on the parent scope (that would then be the controller in question) through

scope.$parent.controllerOnSort(): 

I have another fiddle showing this: http://jsfiddle.net/wZrjQ/2

This solution would have the same effect (with the same criticism in regard to hard-coupling) as the solution in the other answer (https://stackoverflow.com/a/19385937/2572897) but is at least somewhat easier than that solution. If you couple hard anyway, i don't think there is a point in referencing the controller as it would most likely be available at $scope.$parent all the time (but beware of other elements setting up a scope).

I would go for the first solution, though. It adds some little markup but solves the problem and maintains a clean separation. Also you could be sure that $scope.$parent matches the outer directive if you use the second directive as a direct wrapper.

like image 91
Juliane Holzt Avatar answered Oct 30 '22 11:10

Juliane Holzt


The & local scope property allows the consumer of a directive to pass in a function that the directive can invoke.

Illustration of & scope property

See details here.

Here is a answer to a similar question, which shows how to pass argument in the callback function from the directive code.

like image 45
gm2008 Avatar answered Oct 30 '22 10:10

gm2008