Dan Mihai Patrascu
Dan Mihai Patrascu

Reputation: 192

Call angularjs directive function from controller

I've got a directive that needs to do something every now and then, let's say it has to count something. If I use the basic syntax with $scope to bind the count function, it works just fine. but when we switch to the controller as syntax it doesn't bind the function. Here is a working plunker: https://plnkr.co/edit/C2wVaeOm63SLnXBG?open=lib%2Fscript.js&deferRun=1&preview

JS

angular
  .module('plunker', [])
  .controller('MainCtrl', function ($scope) {
    var vm = this;
    vm.name = 'Plunker';
    setInterval(function () {
      $scope.count();
    }, 1000);
    setInterval(function () {
      $scope.count2();
    }, 1000);
    setInterval(function () {
      $scope.count3();
    }, 1000);
  })
  .directive('test', function () {
    return {
      scope: {
        count: '=',
      },
      controller: function ($scope) {
        $scope.i = 0;
        $scope.count = function () {
          $scope.i++;
          console.log($scope.i);
        };
      },
    };
  })
  //with bindToController
  .directive('test2', function () {
    return {
      scope: {
        count: '=',
      },
      bindToController: true,
      controller: function ($scope) {
        var vm = this;
        vm.i = 0;
        vm.count = function () {
          vm.i++;
          console.log(vm.i);
        };
      },
    };
  })
  //with bindToController - the new way
  .directive('test3', function () {
    return {
      scope: true,
      bindToController: {
        count: '=',
      },
      controller: function ($scope) {
        var vm = this;
        vm.i = 0;
        vm.count = function () {
          vm.i++;
          console.log(vm.i);
        };
      },
    };
   });

HTML

<body ng-app="plunker" ng-cloak>
    <div ng-controller="MainCtrl as vm">
      <h1>Hello {{vm.name}}</h1>
      <test count="count"></test>
      <test2 count="count2"></test>
      <test3 count="count3"></test>
    </div>
  </body>

Upvotes: 0

Views: 89

Answers (2)

AvgustinTomsic
AvgustinTomsic

Reputation: 1841

If you are using bindToController syntax, then you should declare your directive count function in directive link function, because binding is happening after directive controller initialisation.

Your modified example here:

  //with bindToController
  .directive('test2', function () {
    return {
      scope: {
        count: '=',
      },
      bindToController: true,
      controller: function ($scope) {
        var vm = this;
        vm.i = 0;
      },
      link:function($scope,$element,$attr,ctrl){
        ctrl.count = function () {
          ctrl.i++;
          console.log('test2',ctrl.i);
        };
      }
    };
  })

Or you can check my modified plunker here: https://plnkr.co/edit/TKTtObbDTcFFC9SS?open=lib%2Fscript.js&deferRun=1

Upvotes: 1

georgeawg
georgeawg

Reputation: 48948

angular
  .module('plunker', [])
  .controller('MainCtrl', function ($scope, $interval) {
    var vm = this;
    vm.name = 'Plunker';
    ̶s̶e̶t̶I̶n̶t̶e̶r̶v̶a̶l̶(̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶)̶ ̶{̶
    $interval(function () {
      $scope.count();
    }, 1000);

Use the $interval service.

AngularJS modifies the normal JavaScript flow by providing its own event processing loop. This splits the JavaScript into classical and AngularJS execution context. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc.

For more information, see

Upvotes: 0

Related Questions