nbsp
nbsp

Reputation: 161

Can not update value inside function of function in angular service

I want share data between controller, so though service, I can easily get and set data. But if a data set by a function in function in service, it's can not update controller's data. like this:

_this.testf = function (){
  _this.test.push(1);
  _this.test.push(1);
  _this.test.push(1);

  $timeout(function (){
    _this.test.push(2);//this can not seen in controller
  }, 1000);
}

The new data still can be update by $watch, but it's not same as reference.

Here is the example code:http://codepen.io/nsbp/pen/MwdqRq

Upvotes: 3

Views: 121

Answers (3)

rob
rob

Reputation: 18513

The problem is that ng-bind will only update when the object you pass into it is replaced with another object. Since you are passing it an array and you are only updating the element of the array ng-bind will not update. You could fix this by either using an ng-repeat or by using {{}} in place of ng-bind.

  <p>
    <span ng-repeat="item in test track by $index" ng-bind="item"></span>
  </p>

http://codepen.io/anon/pen/QbRZxz

Upvotes: 1

David L
David L

Reputation: 33833

The issue occurs because your controller's digest cycle has already ended by the time the timeout period elapses. If you add a quick and dirty check like the following to your pen:

_this.testf = function (){
    _this.test.push(1);
    _this.test.push(1);
    _this.test.push(1);
    $timeout(function (){
      _this.test.push(2);
      alert(_this.test.length);
    }, 1000);
}

You will see that the array IS updated.

As a result, you can either use $watch or $timeout in your controller, or broadcast an event from your directive to your controller to trigger a new digest cycle.

If using $timeout, your assigned binding won't recognize that the data has updated (whereas $watch will if using a deep watch, watching the array length, or if you're using $watchCollection), but you can force it to update by copying the array, which is actually creating an entirely new reference.

.controller('MainCtrl', function($scope, $timeout, List) {
    $scope.test = List.test = [];
    List.testf();
    $timeout(function (){
        $scope.test = angular.copy(List.test); 
    }, 4000);
});

Upvotes: 1

Tom
Tom

Reputation: 7740

This is because the $timeout service is asynchronous.

You could have your service return the value and then in your controller set it in the returned promise, like:

.service('List', function($timeout) {
  var _this = this;

  _this.test = [];
  _this.testf = function (){
    _this.test.push(1);
    _this.test.push(1);
    _this.test.push(1);
    return $timeout(function (){
      _this.test.push(2);
      return _this.test;
    }, 1000);
  }
})
.controller('MainCtrl', function($scope, $timeout, List) {
  List.testf().then(function(test) {
    $scope.test = test;
  });
});

Here is an updated codepen.

Upvotes: 1

Related Questions