Angularjs 从公共服务调用函数时,TypeScript服务未定义
我正在使用带有Angular JS的TypeScript编写一个公共服务,该服务将处理POST并向服务器获取请求 这就是服务的外观: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
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的其他变量对其进行端到端测试。