Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 749
nbsp Avatar asked Nov 26 '25 20:11

nbsp


2 Answers

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.

like image 168
Tom Avatar answered Nov 29 '25 09:11

Tom


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);
});
like image 27
David L Avatar answered Nov 29 '25 09:11

David L



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!