Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 window.postmessage

Tags:

angular

I'm working on an eCommerce application in Angular 2 with a node and express api backend. I'm currently working on the social login section where I am using passport-facebook and jwt for authentication. My code concerns revolve around the Angular 2 portion. When a user clicks on the login/register with facebook button it opens a new tab that begins the facebook login flow. That window will then return the jwt to the opener via window.postMessage. The opener then sends the window a success message and the opened window will close. Everything works correctly but it's not very clean, i.e. I had to hack it up to make it work. Ideally I would call my authorization service to handle the facebook login instead of handling everything in my component but inside the event handler for the window.postMessage 'this' no longer references the component, it references the window object so I can't call the service via 'this'. I can't figure out how to get a reference to the component so I can call the service. Does anyone have any suggestions?

Below is my login component in typescript. I can include other code if need be but I don't know that it is needed.

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;
  }
}
like image 951
user3064073 Avatar asked Jan 03 '17 13:01

user3064073


People also ask

What is window postMessage () used for?

postMessage() The window. postMessage() method safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.

Can I use window postMessage?

window. postMessage() is a safe way to send messages between windows in different domains or origins. One can also post to an IFrame. The data being sent is serialized using the structured clone algorithm and will accept almost any type of simple or complex data.

What is the difference between SendMessage and postMessage?

SendMessage: Sends a message and waits until the procedure which is responsible for the message finishes and returns. PostMessage: Sends a message to the message queue and returns immediately.


2 Answers

You could also use the @HostListener() function decorator:

@HostListener('window:message', ['$event'])
onMessage(event) {
  this.receiveMessage(event);
}
like image 154
bccurry Avatar answered Nov 16 '22 03:11

bccurry


You should change the way you declare the eventListener (by using bind(this) or an anonymous function, or change the way you declare your 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));
   }
}

anonymous function

window.addEventListener("message", () => {
   this.receiveMessage();
}, false)

different declaration of eventHandler

receiveMessage: any = (event: any) =>  {
  //...
}

Take your pick :) With the last option it is easy to detach the eventListener

like image 40
Poul Kruijt Avatar answered Nov 16 '22 01:11

Poul Kruijt