StevieB
StevieB

Reputation: 6533

ES6 + Angular Controller class, getting this is undefined in callback

Consider the following class

class LoginController{
    constructor(authService,$timeout,$state){
        let vm = this;
        this.loading = false;
        this._authService = authService;
        this._$timeout = $timeout;
        this._$state = $state;
        this.loading = false;
        this.statusMessage = null;
    }

    login(){
        this.loading = true;
        this.statusMessage = null;

        let loginModel = {
            UserName : this.username,
            Password : this.password,
            RememberMe : this.rememberMe
        };

        //Login User
        this._authService.login(loginModel).then(function(user){
            //Set User Login & send to Dashboard
            this._authService.setUser(user);
            this._$state.go("dashboard");

        }, function(error){
            const errorMessage = error ? error.Message : "Undefined Login Issue occurred !";
            this.loading = false;
        });
    }
}

Everything is working fine, except for then I hit the error callback function and it gets to this.loading = false; which for some reason this is undefinded.

How do I keep a reference to the Class "this" in the error callback ?

Upvotes: 0

Views: 537

Answers (3)

seahorsepip
seahorsepip

Reputation: 4809

function(error){
    this.loading = false;
}

The this inside the function is a different scope so this refers to the function instead of the parent function.

Solution,

define this as self:

class LoginController{
    constructor(authService,$timeout,$state){
        let vm = this;
        this.loading = false;
        this._authService = authService;
        this._$timeout = $timeout;
        this._$state = $state;
        this.loading = false;
        this.statusMessage = null;
    }

    login(){
        var self = this; //Define this as self

        this.loading = true;
        this.statusMessage = null;

        let loginModel = {
            UserName : this.username,
            Password : this.password,
            RememberMe : this.rememberMe
        };

        //Login User
        this._authService.login(loginModel).then(function(user){
            //Set User Login & send to Dashboard
            self._authService.setUser(user);
            self._$state.go("dashboard");

        }, function(error){
            const errorMessage = error ? error.Message : "Undefined Login Issue occurred !";
            self.loading = false; //Self refers to this of parent scope
        });
    }
}

Upvotes: 0

Michael Whinfrey
Michael Whinfrey

Reputation: 573

This is a very common problem of passing context to a callback function. The generic answer is to declare something like

var self=this; within the context from which you want to keep "this" and then in your callback function reference it like so

function callback () { self.myvariable=true; };

in your particular case you have already declared let vm = this; so you could use vm._authService.setUser(user); vm._$state.go("dashboard");

Upvotes: 0

Niels Steenbeek
Niels Steenbeek

Reputation: 4834

You have to use fat-arrows to keep the scope.

//Login User
this._authService.login(loginModel).then((user) => {
    //Set User Login & send to Dashboard
    this._authService.setUser(user);
    this._$state.go("dashboard");
}, (error) => {
    const errorMessage = error ? error.Message : "Undefined Login Issue occurred !";
    this.loading = false;
});

Upvotes: 4

Related Questions