Jeanluca Scaljeri
Jeanluca Scaljeri

Reputation: 29149

bind callback to directive without isolated scope

When binding a callback function to a directive it is important for me to execute this function with the right context. Now, as long as the directive has an isolated scope it is not a problem

<bar-foo callback="mycontroller.callback()"></bar-foo>

and the directive:

 ...
 scope:{
     callback: '&'
 },
 ...

Without an isolated scope I extract the callback from the $attrs attrubute

$scope.callback = $parse($attrs.callback)($scope);

But, now I cannot do

 <bar-foo callback="mycontroller.callback()"></bar-foo>

Because it will execute the callback directly. What would be the preferred way to solve this ?

DEMO

Upvotes: 2

Views: 868

Answers (3)

georgeawg
georgeawg

Reputation: 48968

In your directive without a scope, just access mycontroller.callback() in the directive template.

.directive('helloWorld', function () {
    return {
        restrict: 'E',
        scope: false,
        //Use THIS
        template: '<button ng-click="mycontroller.callback()">Not isolated</button>',
        //NOT this                  
        //template: '<button ng-click="callback()">Not isolated</button>',
        controller: function ($attrs, $scope, $parse) {
              //$scope.callback = $parse($attrs.callback)($scope);
        }
    }
});

Since the directice has no scope of its own, the template has direct access to the controller which was instantiated with ng-controller="MyCtrl as mycontroller".


what if you want to reuse the directive?

In that case, bind a click handler to the element.

.directive('helloWorld', function () {
    return {
        restrict: 'E',
        scope: false,
        template: '<button>Not isolated</button>',
        link: function (scope, elem, attrs) {
             elem.on("click", function(e) {
                 scope.$eval(attrs.callback, {$event: e});
             });
        }
    }
});

When the directive's element is clicked the Angular expression defined by the callback attribute will be evaluated with the event object exposed as $event.

For more information on $event, see AngularJS Developer Guide -- $event.

Upvotes: 0

PeterS
PeterS

Reputation: 2954

As this scope isn't isolated isn't just a case of calling what you want?

    .directive('helloWorld', function () {
    return {
        restrict: 'E',
        template: '<button ng-click="mycontroller.callback()">Not isolated</button>',
    }
});

and then just calling your directive?

<hello-world></hello-world>

Or am I missing something here?? Specifying the controller with the require attribute is also desirable.

Upvotes: 0

smnbbrv
smnbbrv

Reputation: 24551

First create a function in your controller which explicitly sets the value of this inside of this function:

this.exportableCallback = this.callback.bind(this);

where this.callback is the one you use for the isolated scope.

Second step is setting it as an attribute

<hello-world callback="mycontroller.exportableCallback"></hello-world>

where you do not call the function like you did with isolated scope.

See fiddle.

Another option (if you remove this.callback from your controller) is

this.exportableCallback = function() {
  console.log(this.test);
}.bind(this);

If you want to pass arguments to this function:

this.exportableCallback = function() {
  console.log(arguments);
}.bind(this);

Upvotes: 2

Related Questions