2

I created an Angular directive (see plunkr) as follows:

JS:

angular.module('plunker', []);

angular.module('plunker').controller('MainCtrl', function($scope) {
  $scope.myInputs = {
    email: "[email protected]"
  }
  $scope.logToConsole = function() {
    console.log($scope.myInputs.email);
  }
});

angular.module('plunker').directive('myEmail', function(){
  return {
    restrict: 'E',
    scope: {
      myngmodel: '='
    },
    template: '<input type="email" ng-if="true" ng-model="myngmodel" />'
  };
});

It's called from HTML like this:

<body ng-controller="MainCtrl">
    <my-email myngmodel="myInputs.email"></my-email>
    <input type="button" value="log to console!" ng-click="logToConsole()">
</body>

The issue is as follows:

When I don't put ng-if="true", in the template's textinput, or I use ng-show instead, the binding works correctly.

But when ng-if="true" is present, the binding no longer works; when I edit the field and click button, the old value is always is written to console.

  • Is it a bug or works as designed?
  • Is the issue due to ng-model="myngmodel" not following "the dot rule"?
  • If so, how could I rewrite the directive so that I can pass the data model entry from outside world in the same spirit?
1
  • I'm not sure why it works the way it does, but I have had similar timing issues between ng-if and ng-model. My solution was to wrap the input with another tag, and put the ng-if on that tag, rather than directly on the input. I was never able to figure out why they didn't play well together. Commented Jun 23, 2016 at 16:12

1 Answer 1

1

ng-if creates a child scope - that's the reason why it happens. Here the quote from the documentation:

The scope created within ngIf inherits from its parent scope using prototypal inheritance. An important implication of this is if ngModel is used within ngIf to bind to a javascript primitive defined in the parent scope. In this case any modifications made to the variable within the child scope will override (hide) the value in the parent scope.

So, when you modify the value in your input box - the new value is written to the child scope that inherits the directive's isolated scope:

<my-email myngmodel="myInputs.email" class="ng-isolate-scope">
    <input type="email" ng-if="true" ng-model="myngmodel" class="ng-scope">
</my-email>

The MainCtrl scope var is not updated because it is bound to the directive's isolated scope var - not to its child scope.

The workaround is to use the dot notation - to make sure ng-model reads from and writes to the parent isolated scope of the directive:

directive's template:

<input type="email" ng-if="true" ng-model="myngmodel.email" />

binding to the outer scope:

<my-email myngmodel="myInputs"></my-email>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.