Angular 2 window.postmessage

时间:2017-01-03 13:12:44

标签: angular

我正在开发一个带有节点和表达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;
  }
}

3 个答案:

答案 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);
}