Silver
Silver

Reputation: 5091

Call Angular controller function from directive

I have some Angular 1.4 code I've inherited, which has some bizarre scope issues I'm trying to tidy up - and I'm stuck on a particular one.

I have an ES6 Class controller (Babelified) - in it, I have a method like this

save(data) {
    this.validate(data);
    .... do some more stuff
}

I also have a View and model and html and all that good stuff. In it I have a custom directive for radio buttons - like this

<radio onupdate="vm.save" data="model.myradio1" />

My Radio directive seems to have two bindings for onupdate & data

.directive('radio', () => {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: 'radio',
        scope: {
            data: '=',
            onupdate: '='
        }
    };
})

the template contains

ng-click="radio.onupdate($parent.data);" <-- This looks suspect but no idea what it does!

However - this then explodes in ways I wouldn't have expected:

this.validate is not a function

I can see how this happened - this now refers to the radio buttons scope. But how do I fix it? I'm pretty new to Angular.

Upvotes: 1

Views: 428

Answers (3)

dfsq
dfsq

Reputation: 193311

In order to invoke a controller method from the directive you need to create a "reference" function with & scope configuration:

.directive('radio', () => {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: 'radio',
        scope: {
            data: '=',
            onupdate: '&'
        }
    };
})

Then from directive template you need to call it like this:

ng-click="onupdate({data: $parent.data});"

And finally the usage of the radio directive becomes:

<radio onupdate="vm.save(data)" data="model.myradio1" />

Upvotes: 1

Divyansh Kumar
Divyansh Kumar

Reputation: 26

This is very common problem, when you use HTML element on*** attribute to register listeners. You have to bind controller context to listener function.

<radio onupdate="vm.save.bind(vm)" data="model.myradio1" />

I hope it will work for you.

Upvotes: 0

Theo Itzaris
Theo Itzaris

Reputation: 4681

Hello I stick to your question title 'how to call controller function from directive'.

I've made an example that uses a <select> element and calls the controller function $scope.filterHall() to send the selected object, whenever the user changes value.

Directive (i get the changeHall function and i call it into the template,see below ):

.directive('eventHallsList', function($timeout, $log, $http, $compile) {
    return {
      restrict: 'AE',
      replace: true,
      scope: {
        changeHall: '&',
        items: '=',
        model: '='
      },
      templateUrl: 'mytemplate.tpl.html',
      link: function(scope, element, attrs) {
      }

    }
  });

Template: Into the select element everytime the user selects a value, i call the changeHall() which is bind to the controller's function $scope.filterHall() , and it pass the object.

<select style="color:#337ab7"
        ng-change="changeHall({value:model})" ng-model="model"
        ng-options="item as item.name for item in items">
    <option value=""> choose hall</option>
</select>

live example : http://plnkr.co/edit/iCS0blQjceA4tIIb8bUV?p=preview

Hope helps, good luck.

Upvotes: 0

Related Questions