2017-01-03 9 views
3

私はノードとエクスプレスAPIのバックエンドを持つ角度2の電子商取引アプリケーションで作業しています。私は現在、私がpassport-facebookとjwtを認証に使用しているソーシャルログインセクションに取り組んでいます。私のコードの関心事はAngular 2の部分を中心に回転します。ユーザがfacebookボタンでログイン/登録をクリックすると、facebookログインフローを開始する新しいタブが開きます。そのウィンドウはwindow.postMessageを介してオープナーにjwtを返します。オープナーは、ウィンドウに成功メッセージを送り、開いたウィンドウが閉じます。すべて正常に動作しますが、非常にクリーンではありません。つまり、動作させるためにハックアップする必要がありました。理想的には、コンポーネントのすべてを処理するのではなく、facebookログインを処理するために私の認証サービスに電話するのが理想的ですが、window.postMessageのイベントハンドラの中では 'this'はコンポーネントを参照しません。 'this'経由のサービス。私はコンポーネントへの参照を取得する方法を把握することができないので、私はサービスを呼び出すことができます。誰にも何か提案はありますか?角2 window.postmessage

下記のログインコンポーネントがtypescriptです。必要に応じて他のコードを含めることができますが、必要があるかどうかわかりません。

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; 
    } 
} 

答えて

6

あなたはあなたのeventHandlers宣言する方法bind(this)または匿名関数を使用することによって、あなたがたEventListenerを(宣言方法を変更、または変更する必要があります。

バインド(この)

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) => { 
    //... 
} 

異なる宣言は、PierreDucの.bind(この)技術@とMikeumusさんのコメント@組み合わせるのEventListener

+0

これは完全に機能しました。どうもありがとうございます! – user3064073

+1

角度の 'renderer'クラスでイベントリスナーを追加することもできます。 参照:http://stackoverflow.com/a/35082441/1762493 – Mikeumus

2

を取り外すことは容易である最後のオプションを使用すると:)お好きなところをお選びください:ご希望の場合は

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(); 
    } 
} 

あなたはまだ、直接これを行うことができます:

第2引数は、あなたが現在しているページのURLすべき

window.postMessage("test message data", "http://localhost:8080") 

更新:

this.stopListening = 
    renderer.listen('window', 'message', (even: Event) => { ... }); 
あなたが原点チェックをコメントアウトとJavaScriptコンソール開発者にこれを書き込むことによってそれをテストすることができます。このコマンドは、ページが自分自身からメッセージを受信したと思うようにします。