javascriptangularjsangularjs-forms

ng-model not being updated outside of the scope


I am binding an ng-model to an input, but the value of the variable it's bound to is not being updated outside of the div where that directive is declared:

<div input-field
     ng-if="startTypes.selected.value == 'LocalDate' || startTypes.selected.value == 'LocalDateTime'">
  <input id="date" type="text" ng-model="date" input-date>
  <label for="date">Date</label>
  Date inner scope: {{date}}
</div>
Date outer scope: {{date}}

When selecting a new date, ony the inner date is updated. The outer one remains with the old value (which might be either undefined or not depending if I declared it in the controller, it doesn't matter).

I am using angular-materialize, I am not sure if this is the source of the issue but it doesn't make sense because it is a specific framework for angular to work with the CSS framework materializecss.

This is the component I am using.

Edit:

I have tried declaring date in the controller as $scope.date = new Date() and indeed the current date is loaded in the date picker. However when a date is selected and the model changes, it's only updated locally (inner scope), while in the outer scope the old value remains.


Solution

  • As ng-if creates a child scope which is Prototypically inherited from its current scope while inserting inner template to DOM, hence in this case ng-model getting created inside ng-if's child scope. So what happening is while creating a child scope it carries the primitive datatype values & reference(object) datatypes values to child scope, thats why you can see the outer scope date is getting value inside ng-if date field(only first time). But when you update the value in date you will not see the value gets updated to outer scope. Because the way child scope has create primitive type value not carry their references, where as objects are carried with their references. So you can create a object like $scope.model = {} & then define a property into it, that will work. Because object are carried with their references to child scope, updating inner object would sync the outer object as well(they both are same). This rule is called as Dot Rule by which you can fix your issue.

    $scope.model = {};
    $scope.model.date = new Date();
    

    More convenient way to avoid such kind of scope hierarchy is using controllerAs pattern while using controller on HTML. In this case you shouldn't be using $scope instead you will bind all the properties to controller function context (this). Thereafter when using controller you can use alias of controller to get the values of controller like ng-controller="myCtrl as vm"(here vm is alias of controller which has all information binding to this)

    HTML

    <div input-field
         ng-if="vm.startTypes.selected.value == 'LocalDate' || vm.startTypes.selected.value == 'LocalDateTime'">
      <input id="date" type="text" ng-model="vm.date" input-date>
      <label for="date">Date</label>
      Date inner scope: {{vm.date}}
    </div>
    Date outer scope: {{vm.date}}