Angularjs 从公共服务调用函数时,TypeScript服务未定义

Angularjs 从公共服务调用函数时,TypeScript服务未定义,angularjs,typescript,Angularjs,Typescript,我正在使用带有Angular JS的TypeScript编写一个公共服务,该服务将处理POST并向服务器获取请求 这就是服务的外观: module TBApp { export class apiService { static $inject = ['$http', 'notificationService']; constructor(private $http, private notificationService: notification

我正在使用带有Angular JS的TypeScript编写一个公共服务,该服务将处理POST并向服务器获取请求

这就是服务的外观:

module TBApp {

    export class apiService {

        static $inject = ['$http', 'notificationService'];

        constructor(private $http, private notificationService: notificationService) {

        }

        get(url, config, success, failure) {

            return this.$http.get(url, config)

                .then(result => { this.handleResponse(result, success); }, result => { this.handleError(result, failure) });
        }

        post(url, data, success, failure) {

            return this.$http.post(url, data)

                .then(result => { this.handleResponse(result, success); }, result => { this.handleError(result, failure) });
        }

        handleResponse(result, success) {

                    this.notificationService.displaySuccess(result.data.message);

                    success(result);

        }

        handleError(result, failure) {

            if (result.status === '401') {

                this.notificationService.displayError('Authentication required.');

                //TODO: redirect to login page

            }
            else if (failure !== null) {
                failure(result);
            }
        }
    }
}
因此,在下面显示的控制器中,我想在登录成功时调用
loginCompleted

module TBApp {

    export class loginController extends MyApp.BaseController {

        membershipService: membershipService;
        apiService: apiService;

        static $inject = ['$scope', 'membershipService', 'apiService', '$location'];

        constructor($scope, membershipService: membershipService, apiService: apiService, private $location) {
            super($scope);

            this.scope.user = new User(null, null);

            this.membershipService = membershipService;
            this.apiService = apiService;
        }

        login() {

            // HERE: this.membershipService Is NOT NULL OR UNDEFINED

            console.log(this.membershipService);


            this.apiService.post('/api/account/authenticate', this.scope.user, this.loginCompleted, this.loginFailed);
        }

        loginCompleted(response) {

            //This method will save the logged in user to cookies

            //HERE : this.membershipService Is UNDEFINED

            this.membershipService.saveCredentials(this.scope.user);

            // redirect to home page

            this.$location.path('/');
        }

        loginFailed(response) {
            alert('login failed');
            console.log(response);
        }

    }
}
调用该函数时,除了
this之外,其他所有功能都正常工作。在
loginCompleted()函数中未定义membershipService

我认为这是因为
loginCompleted()
函数是从
apiService
内部调用的,我如何修复它?我做错了什么?

应该是这样的

this.apiService.post(
  '/api/account/authenticate',
  this.scope.user,
  this.loginCompleted.bind(this), this.loginFailed.bind(this)
)
或者

this.loginCompleted = this.loginCompleted.bind(this)
this.loginFailed = this.loginFailed.bind(this)
可以在构造函数中为所有回调/处理程序方法执行

this.apiService.post(
  '/api/account/authenticate',
  this.scope.user,
  this.loginCompleted.bind(this), this.loginFailed.bind(this)
)
或者

this.loginCompleted = this.loginCompleted.bind(this)
this.loginFailed = this.loginFailed.bind(this)

可以在所有回调/处理程序方法的构造函数中完成

@Dawood,你正在失去上下文,我的朋友。导致此问题的原因是您将函数(loginCompleted、loginFailed)作为参数发送,并且当它们执行其关键字
This
时链接到另一个对象

您可以在这里做什么-您可以发送带有绑定上下文的函数(它将始终设置为您定义为第一个参数的对象)

在这种情况下,您发送具有绑定上下文的函数:

this.loginCompleted.bind(this)
this.loginFailed.bind(this) 
将使用绑定到当前类的上下文创建两个新函数

有关此主题的更多信息:

别怪我,我改变了一点代码风格。希望我的回答能有所帮助

更新了下面与评论对话相关的代码

module TBApp {

export class loginController extends MyApp.BaseController {

    static $inject: string[] = ['$scope', 'membershipService', 'apiService', '$location'];

    constructor(
        private $scope: ng.IScope,
        private membershipService: membershipService,
        private apiService: apiService,
        private $location
    ) {

        super($scope);

        this.scope.user = new User(null, null);
    }

    login() {

        // HERE: this.membershipService Is NOT NULL OR UNDEFINED

        console.log(this.membershipService);


        this.apiService.post('/api/account/authenticate', this.scope.user,
            (response) => {
                this.membershipService.saveCredentials(this.scope.user);
                // redirect to home page

                this.$location.path('/');
            },
            (response) => {
                alert('login failed');
                console.log(response);
            });
    }

 }
}

@达伍德,你失去了背景,我的朋友。导致此问题的原因是您将函数(loginCompleted、loginFailed)作为参数发送,并且当它们执行其关键字
This
时链接到另一个对象

您可以在这里做什么-您可以发送带有绑定上下文的函数(它将始终设置为您定义为第一个参数的对象)

在这种情况下,您发送具有绑定上下文的函数:

this.loginCompleted.bind(this)
this.loginFailed.bind(this) 
将使用绑定到当前类的上下文创建两个新函数

有关此主题的更多信息:

别怪我,我改变了一点代码风格。希望我的回答能有所帮助

更新了下面与评论对话相关的代码

module TBApp {

export class loginController extends MyApp.BaseController {

    static $inject: string[] = ['$scope', 'membershipService', 'apiService', '$location'];

    constructor(
        private $scope: ng.IScope,
        private membershipService: membershipService,
        private apiService: apiService,
        private $location
    ) {

        super($scope);

        this.scope.user = new User(null, null);
    }

    login() {

        // HERE: this.membershipService Is NOT NULL OR UNDEFINED

        console.log(this.membershipService);


        this.apiService.post('/api/account/authenticate', this.scope.user,
            (response) => {
                this.membershipService.saveCredentials(this.scope.user);
                // redirect to home page

                this.$location.path('/');
            },
            (response) => {
                alert('login failed');
                console.log(response);
            });
    }

 }
}

bind到底做什么?它为未使用所需上下文调用的函数提供适当的
this
。不是真的,除非函数每秒触发1000次,否则这不应该成为一个问题。它与
this.loginFailed=(…args)=>this.loginFailed(…args)
(加上一些额外的特征)基本相同。bind到底做什么?它为没有使用所需上下文调用的函数提供适当的
this
。不是真的,除非函数每秒触发1000次,否则这不应该成为一个问题。这与
this.loginFailed=(…args)=>this.loginFailed(…args)
(加上一些额外的特征)基本相同。@DawoodAwan,性能没有问题,但在使用TypeScript时,不建议使用bind。这里是关于这一点的。那么如何在不使用bind@DawoodAwan,请参阅更新的代码块。我们替换了anonymus fat arrow函数中一次使用的函数,默认情况下,该函数绑定上下文引用的文章是有偏见的。箭头属性有其缺点。当在类原型上定义该方法时,可以在类实例化之前对其进行模拟/监视,这对于arrow属性是无法做到的(对于这个特定的问题不是这样)。您对原始代码所做的更改使
login
成为一个黑盒,并损害了可测试性,
loginCompleted
loginFailed
不能再被模仿/监视了。@estus,这是TypeScript,在这种情况下,这些函数应该是私有的,私有函数不应该根据定义进行测试。它们应该通过SUT的其他变量进行端到端测试。@DawoodAwan,性能没有问题,但在使用TypeScript时,不建议使用bind。这里是关于这一点的。那么如何在不使用bind@DawoodAwan,请参阅更新的代码块。我们替换了anonymus fat arrow函数中一次使用的函数,默认情况下,该函数绑定上下文引用的文章是有偏见的。箭头属性有其缺点。当在类原型上定义该方法时,可以在类实例化之前对其进行模拟/监视,这对于arrow属性是无法做到的(对于这个特定的问题不是这样)。您对原始代码所做的更改使
login
成为一个黑盒,并损害了可测试性,
loginCompleted
loginFailed
不能再被模仿/监视了。@estus,这是TypeScript,在这种情况下,这些函数应该是私有的,私有函数不应该根据定义进行测试。应通过SUT的其他变量对其进行端到端测试。