0

I am having trouble with binding this inside a promise. I have the following function in angular service:

this.database_view_settings = {'habal':'1'}
this.init = function(){
console.log("1",this.database_view_settings)
return $q((resolve, reject) => {
console.log("2",this.database_view_settings)
    AuthenticationService.getToken().then(function(token){
    $http.get('/api/user/settings/database_view/get',{headers:{'id_token':token}})
    .success(function(data) {
        console.log("3",this.database_view_settings)
        this.database_view_settings = data;
        console.log("login",this.database_view_settings)
        resolve(this.database_view_settings)
    })
    .error(function(data) {
        console.log('Error: ' + data);
        reject(data)
    });
    }.bind(this))


    })
}.bind(this)

My problem is that while at console.log 1 and 2 I see what I want to {'habal':'1'} at console.log 3 I get an undefined and I don't understand why.

fbence
  • 2,025
  • 2
  • 19
  • 42
  • 1
    Why are you doing this? Since you obviously use ES6, then you should use arrows - they are there exactly for that - for all promise callbacks. The snippet is badly formatted and it's not possible to say what's where. But unless you've done `.bind(this)` to each and every callback (and you didn't), you will inevitably lose lexical this at some point. – Estus Flask May 08 '17 at 16:47
  • 2
    Plus it looks like you fell into [The Forgotten Promise](http://taoofcode.net/promise-anti-patterns/#the-forgotten-promise:8f173b15e2d19515fdc8ce931ae539c0) anti-pattern. – sp00m May 08 '17 at 16:50
  • 1
    The [`.success` and `.error` methods have been deprecated and removed from AngularJS](http://stackoverflow.com/questions/35329384/why-are-angular-http-success-error-methods-deprecated-removed-from-v1-6/35331339#35331339). Also there is no need to manufacture a promise with `$q(resolve,reject)` as the $http service already returns a promise. – georgeawg May 08 '17 at 16:52
  • I read up on the arrow thing, should've done earlier ... :D – fbence May 08 '17 at 17:02

2 Answers2

2

This takes the comments added to your question into account:

this.database_view_settings = { 'habal': '1' };

this.init = () => AuthenticationService.getToken()
  .then((token) => $http.get('/api/user/settings/database_view/get', { headers: { 'id_token': token } }))
  .then((data) => {
    this.database_view_settings = data;
    return data;
  });

Then, anywhere else:

this.init().then((data) => {
  // do your stuff with data
}).catch((error) => {
  // oops...
})
sp00m
  • 47,968
  • 31
  • 142
  • 252
  • Much more readable, than my code, and also it works. I had to change one thing: `this.database_view_settings = data.data` is what gives me the data I got in my version (in yours `data` was the whole http response). – fbence May 08 '17 at 17:06
0

I suspect the issue for your particular problem is because you didn't bind this to your $http.get success function. That being said, this is really a lot of binding if your aim is to continuously keep passing the reference of this to nested functions. You can alternatively use something like var _this = this in the outer function and reference the _this variable in all your nested functions. Also, as was suggested by the comments, using arrow function will automatically bind this, to make for cleaner code.

Finally, regardless of the changes, you do not need to bind this on the main this.init function. The this for properties of an object are bound to the object itself, and in this case the object is this.

Sasang
  • 1,261
  • 9
  • 10