我正在开发一个带有节点和表达api后端的Angular 2中的电子商务应用程序。我目前正在使用social-facebook和jwt进行身份验证的社交登录部分。我的代码问题围绕着Angular 2部分。当用户点击登录/注册Facebook按钮时,它会打开一个新的标签,开始登录facebook流程。然后该窗口将通过window.postMessage将jwt返回给opener。然后,开启者向窗口发送成功消息,打开的窗口将关闭。一切正常,但它不是很干净,即我不得不破解它以使其工作。理想情况下,我会调用我的授权服务来处理facebook登录,而不是处理我的组件中的所有内容,但是在window.postMessage的事件处理程序中,'this'不再引用组件,它引用了window对象,所以我无法调用通过'this'服务。我无法弄清楚如何获得对组件的引用,以便我可以调用该服务。有没有人有任何建议?
以下是我在打字稿中的登录组件。如果需要,我可以包含其他代码,但我不知道它是否需要。
import { Component, OnInit, AfterViewChecked } from '@angular/core';
import { AuthService } from './auth.service';
import { Router } from '@angular/router';
import { ILoginUser } from './loginUser.model';
@Component({
moduleId: module.id,
templateUrl: 'login.component.html',
styleUrls: ['login.component.css']
})
export class LoginComponent implements OnInit {
constructor(private _authService: AuthService, private _router: Router) {
if (window.addEventListener) {
window.addEventListener("message", this.receiveMessage, false);
} else {
(<any>window).attachEvent("onmessage", this.receiveMessage);
}
}
ngOnInit() { }
user: ILoginUser = {
username: "",
password: ""
}
error: boolean = false;
success: boolean = false;
errorMessage: string = "";
redirect: boolean = false;
login() {
this._authService.login(this.user).subscribe(data => {
console.log (data);
if (data.success){
this._router.navigate(['/product']);
} else {
this.error = true,
this.errorMessage = data.message
}
}, errorMsg => {
this.error = true;
this.errorMessage = errorMsg;
});
}
receiveMessage(event: any)
{
if (event.origin !== "http://localhost:3000")
return;
localStorage.setItem("token", event.data.token);
localStorage.setItem("username", event.data.username);
(<any>window).popup.postMessage("success", "http://localhost:3000");
}
ngAfterViewChecked() {
//since we can't call the authservice directly we check to see if a redirect flag is set to true
if (this.redirect) {
this._router.navigate(['/product']);
}
}
authFacebook() {
(<any>window).popup = window.open('http://localhost:3000/api/auth/facebook');
//set the redirect flag to true so when angular checks again we can redirect to the products page
this.redirect = true;
}
}
答案 0 :(得分:13)
您应该更改声明eventListener的方式(使用bind(this)
或匿名函数,或更改声明eventHandlers的方式:
绑定(本):
constructor(private _authService: AuthService, private _router: Router) {
if (window.addEventListener) {
window.addEventListener("message", this.receiveMessage.bind(this), false);
} else {
(<any>window).attachEvent("onmessage", this.receiveMessage.bind(this));
}
}
匿名函数
window.addEventListener("message", () => {
this.receiveMessage();
}, false)
eventHandler的不同声明
receiveMessage: any = (event: any) => {
//...
}
选择:)使用最后一个选项可以轻松分离eventListener
答案 1 :(得分:7)
结合@ PierreDuc的.bind(this)技术和@ Mikeumus的评论:
import {Component, OnDestroy, Renderer2} from '@angular/core';
@Component({
selector: 'my-component',
templateUrl: './my_component.ng.html',
})
export class MyComponent implements OnDestroy {
stopListening: Function;
constructor(private renderer: Renderer2) {
this.stopListening =
renderer.listen('window', 'message', this.handleMessage.bind(this));
}
handleMessage(event: Event) {
const message = event as MessageEvent;
// Only trust messages from the below origin.
if (message.origin !== 'http://example.com:8080') return;
console.log(message.data);
}
ngOnDestroy() {
this.stopListening();
}
}
如果您愿意,您仍然可以直接执行此操作:
this.stopListening =
renderer.listen('window', 'message', (even: Event) => { ... });
您可以通过注释原始检查并在开发人员JavaScript控制台中编写它来测试它:
window.postMessage("test message data", "http://localhost:8080")
将第二个arg更新为您当前所在页面的URL。此命令使页面认为它收到了自己的消息。
答案 2 :(得分:5)
您还可以使用@HostListener()函数装饰器:
@HostListener('window:message', ['$event'])
onMessage(event) {
this.receiveMessage(event);
}