0

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>
georgeawg
  • 48,608
  • 13
  • 72
  • 95

2 Answers2

1

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

AvgustinTomsic
  • 1,809
  • 16
  • 22
  • it works just fine. it's bad practice to encapsulate the count() function like this? https://plnkr.co/edit/aHaSoi7l7nu7jnre?open=lib%2Fscript.js&deferRun=1 – Dan Mihai Patrascu Dec 30 '20 at 11:22
0
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

georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • thanks, i used setInterval only for example. Anyway, changed setInterval to $interval and we have the same outcome:https://plnkr.co/edit/X48T2tVmZsHz382q?open=lib%2Fscript.js&deferRun=1 – Dan Mihai Patrascu Dec 30 '20 at 09:29