Loss of this reference in $ scope. $ On event

I am registering "$ routeChangeSuccessEvent" from Angularjs by setting a callback function. When the event is raised, I cannot access the instance of my controllers using "this". The current current instance is unedfined.

My complete TypeScript Code:

export class Ctlr {

    static $inject = ["$rootScope","$route"];

    constructor(private $scope: ng.IRootScopeService) {
        this.Scope = $scope;
        this.Title = "";
        //this.Scope.$on("$routeChangeSuccessEvent", this.onRouteChangeStart);
        this.RegisterEvents();
        }
    private RegisterEvents(): void {
        this.Scope.$on("$routeChangeSuccessEvent",(event: ng.IAngularEvent, args: any) => {
        //this is undefined
            console.log(this);
        });
    }
    public Scope: ng.IScope;
    public Title: string;

    public onRouteChangeStart(event: ng.IAngularEvent, args: any) {
        //this is undefined
        this.Title = args.$$route.name);
    }

}

      

}

I can access the Title property with:

 private RegisterEvents(): void {
        var ref = this.Title;
        this.Scope.$on("$routeChangeSuccessEvent",(event: ng.IAngularEvent, args: any) => {
            ref = args.$$route.name;
        });
    }

      

But this is not a real solution because angularJS does not update its view. I can't seem to find the correct link. If this is not possible, all corner events seem to be off-target - is it impossible?

I also didn't find a thread about this strange behavior. Is there a solution for this problem?

+3


source to share


4 answers


The scope changes on callback, so this

it becomes undefined.

Your other example:

var ref = this.Title;

      

Really just creates -copy-of Title

as it is a primitive type (string). That's why it didn't work either. The update ref

does not update this.Title

.

The usual solution to this is to start defining as:



var vm = this;

...
private RegisterEvents(): void {
    this.Scope.$on("$routeChangeSuccessEvent",(event: ng.IAngularEvent, args: any) => {
    //this is undefined
        console.log(vm);
    });
}

      

Therefore, instead of being used this

everywhere, you should use vm

. Note that vm

you can name it whatever you like. The important part is capturing the reference to this

the scope where this

is what you want to use in the callback. This works because it this

is not a primitive type, because it is an object and instead of taking a copy, it takes a reference.

Another option is to use bind

, which you can apply to any function, this function essentially tells JavaScript what it this

will equate to. For example.

$scope.$on("SomeEventHere", someCallbackFunction.bind(this));

      

This is a matter of preference you are using here, but I usually see people using the method var something = this;

.

+2


source


This is because it always refers to it parent, which is now a function. So if you want you could do this:



private RegisterEvents(): void {
    var ref = this;
    this.Scope.$on("$routeChangeSuccessEvent",(event: ng.IAngularEvent, args: any) => {
        console.log(ref);
    });
}

      

0


source


you can restore this variable:   this.Scope.$on("$routeChangeSuccessEvent",this.onRouteChangeStart.bind(this));

0


source


As noted in other solutions, and using at least TypeScript v1.7 you can use this with the fat arrow, like so:

$scope.$on('some-event', () => { console.log('here `this` is not undefined'); });
$scope.$watch('foo.bar', (a,b) => { console.log('here too...'); }
$scope.$on('$routeChangeSuccessEvent', () => { console.log('here too...'); });

      

But if you want to pass a reference to a function from the same class, you must use the notation .bind(this)

:

$cope.$on('$routeChangeSuccessEvent', this.onRouteChangeStart.bind(this));

      

0


source







All Articles