5

A framework I am using (jQuery Mobile) listens for the change event of textareas to change the markup. This is framework code so I cannot alter it and include the correct AngularJS functions.

I am binding the textarea to a scope variable via ng-model. When the scope variable changes (and thus the textarea content because it is bound) no javascript change event is fired. However without the change event jQuery Mobile cannot change the markup.

Is there a builtin way to let Angular trigger the change event without writing a directive? If I use a directive or ng-change I have to add the corresponding code to every occurrence of a textarea element.

Short example of what I am trying to do (also available as jsFiddle):

<div ng-app="app" ng-controller="Controller">
    <textarea ng-model="textValue"></textarea>
</div>

<script type="text/javascript>
var module = angular.module("app",[]);

module.controller("Controller", function ($scope) {
   $scope.textValue = "Test"; 

   window.setInterval(function () {
       $scope.textValue = $scope.textValue === "Test" ? "Hello World" : "Test";
       $scope.$apply();
   },2000);
});

//Dummy framework code which I do not have access to
document.querySelector("textarea").addEventListener("change", function () {
  alert("changed");
});
</script>

When the model updates, no change event is fired. If you type into the textarea and click outside (a basic textarea change), the change event fires.

Marcus Krahl
  • 674
  • 1
  • 13
  • 28
  • 1
    The addEventListener is native, not a jquery one. Also, the ng-model overrides the change event, specially if the change event is native, and not handled by angular. – Luis Masuelli Jul 31 '14 at 14:58
  • Not sure what you are trying to do. – zs2020 Jul 31 '14 at 15:02
  • A little of topic but can i offer some advice. If it is all possible, should should not combine jQuery Mobile and AngularJS, They don't not play very well together. I think you are going to have a lot of headaches trying to accomplish this, I speak from experience. – Jared Reeves Jul 31 '14 at 15:07
  • The project constraints demand a combination of JQM and AngularJS which worked quite well so far. I was only looking for some "magic" switch which enables the change event propagation. This switch does not seem to exist. – Marcus Krahl Aug 01 '14 at 06:02

3 Answers3

11

You could "override" your ngModel to trigger change event manually: AngularJS - how to override directive ngClick

module.directive("ngModel",function(){
    return {
        restrict: 'A',
        priority: -1, // give it lower priority than built-in ng-model
        link: function(scope, element, attr) {
            scope.$watch(attr.ngModel,function(value){
                if (value){
                    element[0].onchange();
               //   element.trigger("change"); use this for jQuery
                }
            });
        }
      }
});

DEMO

Community
  • 1
  • 1
Khanh TO
  • 48,509
  • 13
  • 99
  • 115
  • Please check your console, I don't use `alert` – Khanh TO Aug 03 '14 at 09:31
  • That is exactly what I was looking for because it adds the correct behaviour without touching all parts of the code – Marcus Krahl Aug 04 '14 at 06:21
  • Note that triggering an event may lead to [potential issues with the $digest cycle](https://stackoverflow.com/questions/33149221/triggerhandler-causing-error-rootscopeinprog-apply-already-in-progress-err)... and necromancy – Patrick Barr Jul 11 '17 at 20:52
  • A tiny question here: This is a directive that shares the parent scope and we are adding a watch. If there is an `ngIf` on that directive's HTML declaration causing it to be removed and re-added multiple times, wouldn't that create a watch leak? Any way one can handle this? There are no directive descructors as far as I know... – user2173353 Aug 28 '17 at 13:59
  • 1
    @user2173353: I think there is no issue. `NgIf` (https://docs.angularjs.org/api/ng/directive/ngIf) directive has priority: 600 which runs before "our" `NgModel` (priority:-1). It means the handler is attached to the scope created by `ngIf`. If `ngIf` removes the scope, the handler is also destroyed because it's attached to the scope directly – Khanh TO Sep 01 '17 at 16:07
3

why dont you use ng-change

<div ng-app="app" ng-controller="Controller">
    <textarea ng-model="textValue" ng-change="changed()"></textarea>
</div>

also use $interval

module.controller("Controller", function ($scope) {
   $scope.textValue = "Test"; 

   var interval = $interval(function () {
       $scope.textValue = $scope.textValue === "Test" ? "Hello World" : "Test";
   },2000);

   $scope.changed = function(){
         alert('changed');
   }

   $scope.$on("$destroy", function(){
       $interval.cancel(interval)
   })
});
harishr
  • 17,807
  • 9
  • 78
  • 125
  • I am not using ng-change because jQuery Mobile itself is listening for the change event (it is framework code). There is always the option to do it "the angular way" but unfortunately jQuery Mobile is not doing it this way. – Marcus Krahl Aug 01 '14 at 05:56
  • but can there not be two listners for the click event?? – harishr Aug 01 '14 at 06:24
  • What click event? The event listener for the change event is bound by jQuery Mobile. – Marcus Krahl Aug 01 '14 at 06:37
  • The change event handler is defined by jQuery Mobile. I cannot use ng-change because I do not want to bind another change handler, but instead trigger the existing change handler. That is why your answer, although well written, is not appropriate for the question – Marcus Krahl Aug 01 '14 at 07:22
0

The addEventListener is native, not a jquery one. Also, the ng-model overrides the change event, specially if the change event is native.

If you want to use ngModel and also listen the change events, use: https://docs.angularjs.org/api/ng/directive/ngChange (be careful: this directive REQUIRES ngModel)

Luis Masuelli
  • 12,079
  • 10
  • 49
  • 87