Angular 2 window.postmessage

use*_*073 7 angular

我正在Angular 2中开发一个带有节点和表达api后端的电子商务应用程序.我目前正在使用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;
  }
}
Run Code Online (Sandbox Code Playgroud)

Pie*_*Duc 16

您应该更改声明eventListener的方式(通过使用bind(this)或匿名函数,或更改声明eventHandlers的方式:

bind(this):

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));
   }
}
Run Code Online (Sandbox Code Playgroud)

匿名功能

window.addEventListener("message", () => {
   this.receiveMessage();
}, false)
Run Code Online (Sandbox Code Playgroud)

eventHandler的不同声明

receiveMessage: any = (event: any) =>  {
  //...
}
Run Code Online (Sandbox Code Playgroud)

拿你的选择:)使用最后一个选项很容易分离eventListener

  • 您还可以使用angular的`renderer`类添加事件侦听器.请参阅:http://stackoverflow.com/a/35082441/1762493 (3认同)

小智 9

您还可以使用@HostListener()函数装饰器:

@HostListener('window:message', ['$event'])
onMessage(event) {
  this.receiveMessage(event);
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*lor 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您愿意,您仍然可以直接执行此操作:

this.stopListening =
    renderer.listen('window', 'message', (even: Event) => { ... });
Run Code Online (Sandbox Code Playgroud)

您可以通过注释原始检查并在开发人员JavaScript控制台中编写它来测试它:

window.postMessage("test message data", "http://localhost:8080")
Run Code Online (Sandbox Code Playgroud)

将第二个arg更新为您当前所在页面的URL.此命令使页面认为它从自身收到消息.