0

I'm writing a web app where tab1 opens tab2 and needs to reload when tab2 is closed but nothing happens when I send the next() value (in debug I saw it get executed only once when the component is initialized). I assume it has something to do with the different browser tabs

the shared service that should allow communication between the two:

  private tabClosedSource = new ReplaySubject<boolean>();
  tabClosedEvent = this.tabClosedSource.asObservable();
  toggleTabClosed() {
    this.tabClosedSource.next(true);
  }

on tab1 :

constructor(private service: ExampleService) {}

ngOnInit() {
    this.service.tabClosedEvent.subscribe(
      event => {
        if (event) {
          location.reload();
        }
      });

  // had some issues with the path starting with '#' so I ended up replacing values
  openTab2() {
    window.open(window.location.href.replace('tab1', 'tab2')); 
  }

on tab2:

constructor(private service: ExampleService) {}

async onContinueClicked() {
  api requests...
  procces data...
  this.service.toggleTabClosed();
  window.close();
}
James Z
  • 12,209
  • 10
  • 24
  • 44
ofek edut
  • 31
  • 1
  • 5

1 Answers1

1

Your requirement is achievable with the help of Broadcast Channel API. Full credit goes to another blog, I've just updated it to suit your needs and by the way I learned some new things too.

First you need to create a service to communicate.

import { Injectable, NgZone } from '@angular/core';
import { MonoTypeOperatorFunction, Observable, Subject } from 'rxjs';
import { map } from 'rxjs/operators';

// helper method to notify zone
function runInZone<T>(zone: NgZone): MonoTypeOperatorFunction<T> {
  return (source) => {
    return new Observable(observer => {
      const onNext = (value: T) => zone.run(() => observer.next(value));
      const onError = (e:any) => zone.run(()=> observer.error(e));
      const onComplete = () => zone.run(()=> observer.complete());
      return source.subscribe(onNext, onError, onComplete);
    });
  };
}

@Injectable({
  providedIn: 'root'
})
export class BroadcastHelperService {

  private broadcastChannel: BroadcastChannel;
  private onMessage = new Subject<any>();

  constructor(
    private ngZone: NgZone) { 
    this.broadcastChannel = new BroadcastChannel('testChannel');
    this.broadcastChannel.onmessage =  (message: any) => { this.onMessage.next(message) }    
  }

  publish(message: string): void {
    this.broadcastChannel.postMessage(message);
  }

  getMessage(): Observable<any> {
    return this.onMessage.pipe(      
      runInZone(this.ngZone),
      map((message: any) => message.data));
  }
}

In tab1 component write code to reload page.

export class Tab1Component implements OnInit {

  worker: any;

  constructor(
    public broadcastHelper: BroadcastHelperService
  ) { }

  ngOnInit(): void {
    this.broadcastHelper.getMessage().subscribe((message: any) => {
      console.log(message);
      if(message === 'close') {
        window.location.reload();        
      }
    })    
  }

}

In tab2 component, write code to broadcast message when the tab is closed.

export class Tab2Component {  

  constructor(
    public broadcastHelper: BroadcastHelperService
  ) { }

  @HostListener('window:beforeunload', ['$event'])
  beforeUnloadHander(event: any) {    
    this.broadcastHelper.publish('close');
  }

}
Krishna Mohan
  • 1,612
  • 3
  • 19
  • 27