Mufazzal
Mufazzal

Reputation: 883

Angular Controller method gives older value of scope

What i am trying to do:

I am creating a directive with input text field. Also taking value and a onChange method as scope parameter. A controller is wraped over this directive as u see in the html, this controller provides implementation of onChange method and a model for value.

Issue i am facing:

see line console.log($scope.data): This statement prints the older value of data object in the console.

Any guess why it is happening.

JS codde

   angular.module('APP', [])
    .directive('txtInput', function () {
      return {
        restrict: "E",
        replace: true,
        scope: {
            value: '=',
            onChange: '&',
        },
        template: 
          '<div>'+
            '<input type="text" '+
              'ng-change = "onChange()" '+
              'ng-model="value" />'+
          '</div>',
    }
})
.controller('pageCtrl', function($scope) {
  $scope.data = {
    userPost: "sdsds",
  }
  $scope.onPostInputChange = function() {
    console.log($scope.data)
  }

})

Here is the HTML

<div ng-app='APP' ng-controller="pageCtrl">
    <txt-input 
        value="data.userPost"
        on-change="onPostInputChange()"> </txt-input>
  </div>

Also check the copy at JSFIDDLE

Upvotes: 4

Views: 152

Answers (1)

georgeawg
georgeawg

Reputation: 48968

This is a common problem when using both two-way = binding and expression & binding in directives and components with isolate scope. Two-way binding uses a watcher which transfers values from isolate scope to parent scope. The dirty-checking and execution of the watchers happens after any invocation of the expression binding. There is a delay between when the expression executes and when the value is transfered to the parent scope.

The solution is to expose the value as a local when the expression binding is invoked. Any expression will then have that value available immediately instead of waiting for a digest cycle.

angular.module('APP', [])
    .directive('txtInput', function () {
      return {
        restrict: "E",
        replace: true,
        scope: {
            value: '=',
            onChange: '&',
        },
        template: 
          '<div>'+
            '<input type="text" '+
              //'ng-change = "onChange()" '+
              //expose value as a local
              'ng-change = "onChange({$value: value}) '+
              'ng-model="value" />'+
          '</div>',
    }
})

HTML

<div ng-app='APP' ng-controller="pageCtrl">
    <txt-input 
        value="data.userPost"
        on-change="onPostInputChange($value)">
    </txt-input>
</div>

In the parent controller, use the value furnished as an argument to the function:

angular.module('APP').controller('pageCtrl', function($scope) {
  $scope.data = {
    userPost: "sdsds",
  }
  $scope.onPostInputChange = function(value) {
    //console.log($scope.data)
    console.log(value);
  }
})

The DEMO in JSFiddle

Upvotes: 3

Related Questions