ngChange is called when model changed programmatically
Asked Answered
P

4

11

I have a problem when angular's ng-change is called when model is changed programmatically.

$scope.sendMessage = function() {
    $scope.message = "Message sent";
}

$scope.confirmed = true;
$scope.mySelectBox = $scope.selects[1];

<select ng-model="mySelectBox"
        ng-options="item.name for item in selects track by item.name"
        ng-change="sendMessage()">
</select>

Here is code example: http://plnkr.co/edit/R4MO86ihMrauHXhpCMxi?p=preview

Message should be null, because sendMessage shouldn't be called. Model is changed programmatically.

Prerecord answered 15/6, 2015 at 13:16 Comment(5)
Hm, it might be something weird with the way the ng-select is intializing. The ng-change works as expected and does not fire when the dropdown value is changed programmatically after intialization. I've made a fiddle based on your demo.Joiejoin
Yes, very strange. Probably could be reported as an issue?Prerecord
Hello, I'm facing the same kind of issue in another context when changing programmatically the model with values collected through an HTTP request (see link below). Did you find a solution or did you declare the bug to the Angular JS team in GitHub ? TIA. See here.Baluster
We removed track by and added additional property to options during init phase.Prerecord
This issue happends only when you set NULL to your ng-model, kTT's answer solved this issue nicely.Unite
F
3

According to docs, you're right.

https://docs.angularjs.org/api/ng/directive/ngChange

but this seems to be a bug caused by the order in which the events are hooked up

The best way round it - with resorting to js handler (onchange)

$scope.$watch("mySelectBox", function(a,b) {
    if (a.name!=b.name) {
       $scope.message = "Message sent! (old="+b.name+', new='+a.name+')';
    }
  });

See plunk http://plnkr.co/edit/2ZbxS1tszppR9SrNqxVB?p=preview

HTH

Floury answered 15/6, 2015 at 13:39 Comment(0)
H
17

You can try with ngModelOptions. See this plunker for reference http://plnkr.co/edit/BdKx62RW5Ls2Iz1H3VR1?p=preview.

In my example I used ng-model-options="{ updateOn: 'change', debounce: { change: 0 } }" and it seems to work. It only runs function provided in ngChange when I change the selection. On initialize phase message stays empty.

Hi answered 15/6, 2015 at 13:53 Comment(1)
This sould be marked as correct answer because you are not forced to modify function that is called by ng-change. Thank you!Unite
P
4

The ng-change callback is changed on each model change, and it treats the initial setup as such change. What you might want to do is to run desired code only after user interacts with it. You can check the $touched property of the field:

<form name="exampleForm" ng-controller="ExampleController">
  <select ng-model="mySelectBox" name="mySelectBox"
          ng-options="item.name for item in selects track by item.name"
          ng-change="sendMessage()">
  </select>
  <p>message = {{message}}</p>
</form>


$scope.sendMessage = function() {
    if ($scope.exampleForm.mySelectBox.$touched) {
        $scope.message = "Message sent";
    }
}
Pages answered 15/6, 2015 at 13:38 Comment(0)
F
3

According to docs, you're right.

https://docs.angularjs.org/api/ng/directive/ngChange

but this seems to be a bug caused by the order in which the events are hooked up

The best way round it - with resorting to js handler (onchange)

$scope.$watch("mySelectBox", function(a,b) {
    if (a.name!=b.name) {
       $scope.message = "Message sent! (old="+b.name+', new='+a.name+')';
    }
  });

See plunk http://plnkr.co/edit/2ZbxS1tszppR9SrNqxVB?p=preview

HTH

Floury answered 15/6, 2015 at 13:39 Comment(0)
A
0

You are providing value to model in controller ,so whenever you will set value of model which is matching with list it will call ng-change:

See updated plunker: http://plnkr.co/edit/f3xGmKesLFbzti56WLyH?p=preview

Aboutface answered 15/6, 2015 at 13:35 Comment(1)
That's not an answer for that question.Hi

© 2022 - 2024 — McMap. All rights reserved.