Ivan
Ivan

Reputation: 872

Changing `ng-required` calls `ng-change`

I have a strange behavior in my app using AngularJS 1.5.8:

plunker (https://plnkr.co/edit/zaHVJeK8hdxk2gaOL9Pf?p=preview) and video(http://recordit.co/eszvfdfC9S)

expected behavior?

Please let me know if it's a bug or not. If not then why changing ng-required calls ng-change NOT always or even at all?

ANSWER IS FOUND-------------------------------------------------------------------------------------------------------

NgModelController has two properties: $viewValue (value entered by user) and $modelValue (value bound to your model). When the value entered by the user fails validation, NgModelController sets the model to undefined.

In AngularJS 1.3, they added the ng-model-options directive. It lets you configure how/when the model gets updated. You can use the allowInvalid option to prevent your model from being set to undefined:

ng-model-options="{allowInvalid: true}"

Upvotes: 9

Views: 2024

Answers (4)

Farzad Salimi Jazi
Farzad Salimi Jazi

Reputation: 760

I think this is the reason. put an alert inside ng-change like this.

this.onChange = function() {
        alert(this.val);
        this.output+='Changed\n';
      }

When you empty the box after completing it the value change between two values:

undefined  when is required 
''         when is not required 

So By changing the radio box you call the ng-change, At the beginning you have

However when you have not started to type in the text box , radio box does not change the input value , because ng-change is for input. In the beginning we have undefined --> undefined so nothing changed. then when you empty the input you have '' ---> undefined.

Actually if you put this in your controller you get call ng-change at the beginning too.

this.val ='';

So if you replace your controller with this , you see ng-change is called even at the beginning.

angular.
  module('myApp', []).
  component('greetUser', {
    templateUrl: 'tmpl.html',
    controller: function GreetUserController() {
      this.output='';
      this.isRequired = false; 
      this.val ='';
      this.onChange = function() {
        this.output+='Changed\n';
      }
    }
  }); 

Upvotes: 0

Deep
Deep

Reputation: 9804

This is happening because the ng-required is changing the attached modal value to undefined from blank when the required is set to false, due to this ng-change is fired since the modal changes.

Check in the plunker i have console.log the value of input and you can see the change of modal clearly.

angular.
  module('myApp', []).
  component('greetUser', {
    templateUrl: 'tmpl.html',
    controller: function GreetUserController() {
      this.output='';
      this.isRequired = false; 

       console.log(this.val);

      this.onChange = function() {

        console.log(this.val);
        this.output+='Changed\n';
      }
    }
  });

plunker : https://plnkr.co/edit/6IeIjIDahcmBIU4KSASJ?p=preview

Now the question arises that why not the on load/ first time the change event is not firing up that is because we are using this object rather then $scope.

Here 'this' vs $scope in AngularJS controllers

is a very good example which explains why until we manually enter the value in the input at least once the change event is not firing up.

in short this is happening because ng-change/ng-model works with scope variables. Once you manually enter value in the input element, the model binding happens with the scope, and the ng-change event start firing up.

Upvotes: 2

user2414751
user2414751

Reputation: 186

You should add

        ng-model-options="{allowInvalid: true}"

So the final result will be

<input type="text" 
    ng-change="$ctrl.onChange()" 
    ng-required="$ctrl.isRequired"
    ng-model-options="{allowInvalid: true}"
    ng-model="$ctrl.val"
    />

Upvotes: 8

Hereblur
Hereblur

Reputation: 2174

I think you misunderstanding.

ng-required and ng-change is different things. doing different purpose, and not calling each other.

ng-change is calling your function no matter what it's empty or not. It's call your method by it self, regarding to changes happening in the input.

ng-required is just checking value if it's empty or not, If it is empty, mark it as invalid.

In order to get what you want, you have to check the validity inside the onChange function.

this.onChange = function() {

    if( !$scope.$ctrl.form.$valid ) return;

    this.output+='Changed\n';
}

Upvotes: 0

Related Questions