Search code examples
angularwindownavigatoronbeforeunloadsendbeacon

proper way of using beforeunload to send a beacon on window close using angular 13


Im trying to send a beacon when a user closes the browser window that they are viewing on my site. I am using Angular 13 and using the window and navigator javascript apis to do it.

First I know call back crazy in my init post. Its going to get fixed just not something I care about right now.

ngOnInit(): void {
    window.scrollTo(0,0);
    this.route.params
      .subscribe(
        (params: Params)=>{
          this.creatorslug = params['creatorslug'];
          this.userobject = this.authservice.getUser$()
            .subscribe(
              (object : any)=>{
                this.userobject = object;
                this.http.get(environment.add_user_to_content_creator_shochat_stream + this.creatorslug)
                  .subscribe(
                    (req: any)=> {
                      this.shochatobject = req;
                      window.addEventListener('beforeunload', ev => {
                        const payload = {
                          shochatid: this.shochatobject['shochatid']
                        };
                        if(!this.properleave){
                          //@ts-ignore
                          navigator.sendBeacon(environment.receive_beacon_user_leave_shochat, payload)
                        }

                        });
                      this.loaded = true;
                      this.syncsubscription = this.tss.receiveSyncClient()
                        .subscribe(
                          (req: any) => {
                            if(req != null){
                              this.syncClient = req;
                              this.syncClient.document(this.tss.setdocumentname(this.shochatobject['contentcreatordisplayname'])).then((doc) => {
                                if(doc.data.killshochat){
                                  this.leaveshochat();
                                }
                              });

                              this.syncClient.document(this.tss.setdocumentname(this.shochatobject['contentcreatordisplayname'])).then((doc)=>{
                                doc.on('updated', (event)=>{
                                  if(event.data.killshochat){
                                    this.leaveshochat();
                                  }
                                });
                              });
                            }

                          });
                    });
              });
        });
  }

Notice on the init function of the component im sharing I define the beforeunload listener

window.addEventListener('beforeunload', ev => {
                            const payload = {
                              shochatid: this.shochatobject['shochatid']
                            };
                            if(!this.properleave){
                              //@ts-ignore
                              navigator.sendBeacon(environment.receive_beacon_user_leave_shochat, payload)

the proper leave boolean is in regards to a flag that gets called if the user leaves the page correctly.

leaveshochat(){
    this.properleave = true;
    // @ts-ignore
    const url = environment.user_leave_shochat + this.shochatobject.shochatid;
    this.http.delete(url)
      .subscribe(
        (req: any)=>{
          // @ts-ignore
          this.router.navigate(['user-services', 'user-shochat-end', this.shochatobject.shochatid]);
        });
  }

but what happens when I test closing the browser window without clicking the button that uses the leaveshochat() function the beacon does not send. I imagine I'm doing something silly.

update I read this article and then tried this but still no change in action

@HostListener('window:beforeunload',['$event'])

  unloadHandler(event: Event){
    const payload = {
      shochatid: this.shochatobject['shochatid']
    };
    if(!this.properleave){
      //@ts-ignore
      navigator.sendBeacon(environment.receive_beacon_user_leave_shochat, payload)
    }
  }

Solution

  • Assuming that this problem doesn't come from mobile device? For example, these events will not fire in the following situation:

    1. The user loads the page and interacts with it.
    2. When they are finished, they switch to a different app, instead of closing the tab.
    3. Later, they close the browser app using the phone's app manager.

    The other thing I don't see here is what is this.properleave? Are you sure it is in the correct state when user is leaving? Anyway, I tried to test it and I am able to post message content beforeunload.

      ngOnInit() {
        this.subscribeToNativeNavigation();
      }
    
      private subscribeToNativeNavigation() {
        fromEvent(window, 'beforeunload')
        .subscribe((e) => {
          const message = 'Sending data';
          (e || window.event).returnValue = !message;
          console.log(message)
          navigator.sendBeacon('/log', message);
          return message;
        })
      }
    
      refreshPage() {
        location.reload();
      }
    

    Example: https://stackblitz.com/edit/beforeunload-warning-kmbxjl?file=src%2Fapp%2Fapp.component.ts