简体   繁体   English

TypeScript:未捕获的TypeError:this.fnName不是函数

[英]TypeScript: Uncaught TypeError: this.fnName is not a function

I am working with Typescript and have an ajax call that on Success is calling another function \\ method. 我正在使用Typescript,并且有一个ajax调用,该调用在成功时正在调用另一个函数\\方法。

 deleteTheseSuccess(data) {
     new Fe.Upsm.Head().showGlobalNotification("Selected Items Deleted");
     this.refreshPrintQueueGrid(); <== this is there the error existst
     (window as any).parent.refreshOperatorPrintQueueCount();
 }

the method call that I have pointed out above is trying to call 我上面指出的方法调用正在尝试调用

refreshPrintQueueGrid() {
    $("#PrintQueueGrid").data("kendoGrid").dataSource.read();
    this.refreshPrintQueueStats();
}

This compiles without any issues in VS2017 and produces the JavaScript files accordingly 这将在VS2017中编译没有任何问题,并相应地生成JavaScript文件

and this is the call in the JavaScript output 这是JavaScript输出中的调用

PrintQueue.prototype.refreshPrintQueueGrid = function () {
    $("#PrintQueueGrid").data("kendoGrid").dataSource.read();
    this.refreshPrintQueueStats();
};

The exact error that I get is 我得到的确切错误是

Uncaught TypeError: this.refreshPrintQueueGrid is not a function. 未捕获的TypeError:this.refreshPrintQueueGrid不是函数。

I would be grateful if anyone can help me understand what is going wrong here and what would cause this as I will have this in a number of places over my application. 如果有人可以帮助我了解这里出了什么问题以及什么原因会导致我的不便,我将不胜感激,因为我将在我的应用程序中的许多地方找到它。

--- Edit compiled code -编辑已编译的代码

PrintQueue.prototype.refreshPrintQueueGrid = function () {
            $("#PrintQueueGrid").data("kendoGrid").dataSource.read();
            this.refreshPrintQueueStats();
        }

--- Edit 2 -- Class -编辑2-班级

namespace Fe.Upsm {
export class PrintQueue {


    callingView: string

    constructor(callingView: string) {

        this.callingView = callingView;

        this.documentReadyObjects();

    }

    refreshPrintQueueGrid() {
        $("#PrintQueueGrid").data("kendoGrid").dataSource.read();
        this.refreshPrintQueueStats();
    }

    deleteThese(ids) {

        var jsonObj = {
            ids: ids
        }

        var dataAccess = new DataAccess.AjaxDataAccessLayer(Fe.Upsm.Enums.AjaxCallType.Post,
            Fe.Upsm.Enums.AjaxDataType.json,
            "../../PrintQueue/DeletePrintQueueItems",
            jsonObj);

        dataAccess.ajaxCall(this.deleteTheseError, this.deleteTheseSuccess);

    }

    deleteTheseSuccess(data) {
        new Fe.Upsm.Head().showGlobalNotification("Selected Items Deleted");
        this.refreshPrintQueueGrid;
        (window as any).parent.refreshOperatorPrintQueueCount();
    }

    deleteTheseError(xhr) {
        alert("An Error Occurred. Failed to delete print queue items");
    }



}

} }

The problem is that in your ajax callback 问题是在您的ajax回调中

dataAccess.ajaxCall(this.deleteTheseError, this.deleteTheseSuccess);

method this.deleteTheseSuccess loose 'this' context (because ajax call it). 方法this.deleteTheseSuccess松散了'this'上下文(因为ajax调用了它)。

You can wrap this function by other that contains this as self variable and pass it to dataAccess.ajaxCall 你可以用其他此功能包含thisself变量,并传递给dataAccess.ajaxCall

EDIT 编辑

Try something like this (i write code from head so test it): 尝试这样的事情(我从头开始编写代码,因此对其进行测试):

Add it to class PrintQueue following method 将其添加到类PrintQueue以下方法

public deleteTheseSuccessWrapper() {
    let self = this;
    return () => { self.deleteTheseSuccess(); };
}

And use it in deleteThese method by: 并通过deleteThese方式在deleteThese方法中使用它:

dataAccess.ajaxCall(this.deleteTheseError, this.deleteTheseSuccessWrapper());

EDIT - version 2 编辑-版本2

as @estus point out in comments: Why is deleteTheseSuccessWrapper needed? 正如@estus在评论中指出的: 为什么需要deleteTheseSuccessWrapper? we can try to omit it just by using fat-arrow: 我们可以尝试仅使用fat-arrow来忽略它:

dataAccess.ajaxCall(this.deleteTheseError, () => { this.deleteTheseSuccess() });

So we have oneliner solution - I write above code from head but I think it should also work 所以我们有了oneliner解决方案-我从头开始编写上述代码,但我认为它也应该有效

deleteTheseError and deleteTheseSuccess methods are passed as callbacks. deleteTheseErrordeleteTheseSuccess方法作为回调传递。 As explained in related umbrella question , there are ways to bind them to proper this context. 如在相关的说明伞的问题 ,也有约束他们适当的方式this方面。

It's possible to define these methods as arrow functions, but as this answer explains, a more universal way is to define them as prototype methods and bind them in class constructor: 可以将这些方法定义为箭头函数,但是正如此答案所解释的,一种更通用的方法是将它们定义为原型方法并将其绑定到类构造函数中:

constructor(callingView: string) {
    this.deleteTheseError = this.deleteTheseError.bind(this);
    this.deleteTheseSuccess = this.deleteTheseSuccess.bind(this);
    ...
}

Besides arrow methods, TypeScript also offers an option to use method decorators, eg from bind-decorator package. 除箭头方法外,TypeScript还提供使用方法装饰器的选项,例如, bind-decorator包中的方法。 This provides a nicer syntax for .bind(this) : 这为.bind(this)提供了更好的语法:

import bind from 'bind-decorator';

...
@bind
deleteTheseSuccess(data) {...}

@bind
deleteTheseError(xhr) {...}
...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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