0

I have this custom directive:

eDiscovery.directive('customHighlightUsername', function () {

  return {

    restrict: 'A',

    link: function ($scope, elem, attrs) {

      elem.bind('change', function () {
        console.log('bind works');       // this does not work
      });

      elem.on('blur', function () {
        console.log('blur works');       // this works
      });

      elem.on('change', function () {
        console.log('change works');    // this does not work
      });

    }
  }
});

and here is my HTML:

   <input custom-highlight-username
     type="text"
     style="display: initial;"
     ng-model="assignSelectedQuestionsInput"
     placeholder="Assign users to selected questions:"
     class="form-control">

For whatever reason, the on('blur') callback is working in my directive, but the on('change') and bind('change') callbacks do not fire as expected. As you can see, this is a text input field - when new characters are entered into the field, I would expect the change callbacks to fire.

Does anyone know why that might happen?

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817

2 Answers2

0

You could achieve this by using $scope.$watch like in this runnable demo fiddle. This is the common way in AngularJS to listen to ngModel changes when ng-change is not available.

View

<div ng-controller="MyCtrl">
  <input custom-highlight-username
       type="text"
       style="display: initial;"
       ng-model="assignSelectedQuestionsInput"
       callback="someFunction(param)"
       placeholder="Assign users to selected questions:"
       class="form-control">
</div>

AngularJS application

var myApp = angular.module('myApp',[]);

myApp.controller('MyCtrl', function ($scope) {
        $scope.someFunction = function (someParam) {
        console.log(someParam);
    }
});

myApp.directive('customHighlightUsername', function ($timeout) {

  return {

    restrict: 'A',
    scope: {
      "model": '=ngModel',
      "callbackFunction": '&callback' 
    },


    link: function (scope, elem, attrs) {

        scope.$watch('model', function (newValue, oldValue) {
          if (newValue && oldValue) {
            console.log('changed');
            scope.callbackFunction({ param: 'log test'});
          }
        });

        elem.on('blur', function () {
          console.log('blur works');
        });
    }
  }
});
lin
  • 17,956
  • 4
  • 59
  • 83
  • 1
    I hear this every time. We using over 1k of watches in a single view and it still runs perfect. Give me a link to show me the limitations please. – lin Mar 16 '17 at 22:05
  • And needing a watcher usually means a bad architecture. – epascarello Mar 16 '17 at 22:39
  • just curious, is the $scope passed to the link method, the same $scope as in the controller? – Alexander Mills Mar 17 '17 at 00:50
  • this works for me, I am very surprised the setup in my question does not work. However, once I get the newValue/oldValue - I need to call a controller method, how can I do that? The $scope passed to link the directive is not the same $scope as the controller from the HTML. – Alexander Mills Mar 17 '17 at 00:57
  • @AlexanderMills updated. Now you can call a ctrl function inside your directive. I dont know why you need this, but it works. =) – lin Mar 18 '17 at 22:55
0

From what you posted, the change event should be fine. Now the change event is not triggered when the value is updated by code.

function customHighlightUsername () {
  return {
    restrict: 'A',
    link: function(scope, elem, attrs) {
      elem.bind("change", function() {
        console.log('change');
      });
      elem.bind("blur", function() {
        console.log('blur');
      });
      elem.bind("input", function() {
        console.log('input');
      });
    }
  }
}

angular.module('myApp', []);
angular
  .module('myApp')
  .directive('customHighlightUsername', customHighlightUsername);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<div ng-app="myApp">
  <input custom-highlight-username type="text" />
</div>
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • I know I will be downvoted for saying it works, just getting the runnable example there. – epascarello Mar 16 '17 at 22:14
  • Haha =) .. nice! But, is the event binding also destroyed when the directive will be destroyed? Still waiting for your $watch limitations example =) http://jsfiddle.net/ac022rqs/ – lin Mar 16 '17 at 22:24
  • So you hook up destroy. That is not part of the OP's question. There is no need for a watch. There is a bug in OPs code somewhere and a watch is not the answer. – epascarello Mar 16 '17 at 22:40
  • `$watch` will be destroyed in the moment the directive has been destroyed while your binding will stay/or stack after the directive has been destroyed or reassigned (bad architecture). You still did not answer my questions. Please show me a limitations of $watch and explain why it is better to have a bind stack (your solution) than a $watch. – lin Mar 16 '17 at 22:45