2

I'm trying to learn to use controller as more often in my angular controllers and ran into a scoping issue when updating a scope from inside another function:

.controller('profileCtrl', function(ProfileData, Restangular){
  // ProfileData comes from router.resolve

  this.user = ProfileData;

  // I want to update the data with a button click or something
  this.refresh = function(id){
    Restangular.one('users', id).get().then(function(resp){
      this.user = resp;
    })
  }
});

The this.user = resp doesn't actually refer to the same this in this.user = ProfileData. I don't know what it refers to, maybe the function?

I fixed this by injecting scope and then changing my update function:

  this.refresh = function(id){
    Restangular.one('users', id).get(params).then(function(resp){
      $scope.profile.user = resp;
    })
  }

The problem I have with this approach is that it depends on me calling the controller myCtrl as profile.

Is there a way to update this.user from within my function without injecting scope?

user2936314
  • 1,734
  • 4
  • 18
  • 32
  • Since `this` always refers to the current closure, I don't think it is possible without the use of `$scope`. – Clawish Sep 18 '14 at 00:19
  • 1
    You understood the problem, `this` is not what you think it is inside the callback, because thecallback function is executed from a different context. Just cache `this` to another variable and use it inside the callback.. Or in your controller just do:- `var viewModel = this` and use `viewModel` across instead of using `this` – PSL Sep 18 '14 at 00:19
  • 1
    Check out this answer.. http://stackoverflow.com/questions/25716048/confusion-about-this-keyword-in-angular-controller-as-syntax/25716069#25716069 – PSL Sep 18 '14 at 00:21

2 Answers2

2

this gets overridden depending on the execution context.

Instead, you should save this in a temp variable and reference it within your closure.

.controller('profileCtrl',      function(ProfileData, Restangular){
  // ProfileData comes from router.resolve

  var $this = this;
  $this.user = ProfileData;

  // I want to update the data with a button click or something
  $this.refresh = function(id){
    Restangular.one('users', id).get().then(function(resp){
      $this.user = resp;
    })
  }
});

That way, this is always what you expect it to be

Michael Kang
  • 52,003
  • 16
  • 103
  • 135
1

You can always use function binding to help you out, but the problem with it is that you therefore lose access to any of the methods or values on what would be the default this. For example,

.controller('profileCtrl', function(ProfileData, Restangular){
  // ProfileData comes from router.resolve

  this.user = ProfileData;

  // I want to update the data with a button click or something
  this.refresh = function(id){
    Restangular.one('users', id).get().then(function(resp){
      this.user = resp;
    }.bind(this)); //The 'this' in the .bind() function is the 'this' of the data outside the function. Weird, I know.
  }
});

Unsure if this particularly resolves your problem, but it's one method I got very accustomed with when I was dealing with MooTools a lot.

Jhecht
  • 4,407
  • 1
  • 26
  • 44