简体   繁体   中英

Access TypeScript functions from JavaScript

I want to use TypeScript with jsTree. How can I call the setCurrentNode function in the bound jsTree function?

class MyController {
    thescope: any;
    static $inject = ['$scope'];

    constructor($scope) {
        $scope.vm = this;
        this.thescope = $scope;

        (<any>$("#demo2")).jstree({
             .bind("select_node.jstree", function (e, data) {
              // how can I call setCurrentNode(data) here?
             }
        });

    }


    setCurrentNode(node: any): any {
        ... // do Stuff in this typescript function
    }
}

Solution:

(<any>$("#demo2")).jstree({
         .bind("select_node.jstree", this.setCurrentNode.bind(this) )
         }

public setCurrentNode(e:any,data: any): any {
   ...
}

I'm not completely sure, so please correct me if I'm wrong, but wouldn't the use of the lamba expression solve this problem as well?

As follows:

class MyController {
    thescope: any;
    static $inject = ['$scope'];

    constructor($scope) {
        $scope.vm = this;
        this.thescope = $scope;

        (<any>$("#demo2")).jstree({
             .bind("select_node.jstree", (e, data) => {
                 this.setCurrentNode(e, data);
             }
        });

    }

    setCurrentNode(e: any, node: any): any {
        ... // do Stuff in this typescript function
    }
}

The lambda ( => ) expression will make sure the function is executed in the same scope as the scope you're defining it in. If you'd look at the compiled JavaScript code you'll see he will keep a reference to the constructor scope and will call setCurrentNode on that scope. Simplified example:

var _this = this;
$("#demo2").jstree({
     .bind("select_node.jstree", (e, data) => {
         _this.setCurrentNode(e, data);
     });

I believe this would solve your problem?

On a side note, you should look for a jsTree definition file or at least add a stub declaration yourself so you don't need to cast JQuery to any. Just my 2cts, it looks ugly to me.

As per Anzeo's suggestion to prevent the need for casting $ to any the following is all you need to get you started :

interface JQuery{
        jstree:Function;
}

What it happens is that the inner jsTree callback is overwriting the this initial reference to the instance object.

There are two safe ways to solve this:

1- By the use of the arrow function as pointed by @Anzeo, which I don't recommend and I never use since if you need to have another nested callback then you can have a this reference to the innermost event object.

2- By caching the this reference to the instance object like:

class MyController {
    thescope: any;
    static $inject = ['$scope'];

    constructor($scope) {
        // Caching the reference for using it in the inner callbacks.
        var self = this;

        $scope.vm = this;
        this.thescope = $scope;

        (<any>$("#demo2")).jstree({
             .bind("select_node.jstree", function (e, data) {

              // Call to the instance method here!
              self.setCurrentNode(/*Node params here*/);
             }
        });

    }


    setCurrentNode(node: any): any {
        ... // do Stuff in this typescript function
    }
}

I recommend you to stick with 2 since it will work though any nesting level and you can have the this in each nested callback pointing to the right event object.

See Javascript 'this' overwriting in Z combinator and every other recursive function for more references since the problem is the same as here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM