Strange behaviour when switching pages with angular router

so im using a bluetooth barcodescanner with my app,

this is the code i use to read its values (works with every barcodescanner in text mode)

i have a page named “list”

window.addEventListener("keypress", function (e) {  // barcodescanner input
      if (e.keyCode != 13) {
        This.barcodeText += e.key; //text gets added
      } else {
        // do whatever
        This.barcodeText = ""; //reset variable
        This.router.navigateByUrl('/input');
      }
    })

the problem arises when i go to the “input” page and then dont touch/click anything and use the barcode scanner again , the listener in the “list” page still receives the input …

this behaviour also holds true for anything else , unless you actually touch the phones display in the new page the old page is still receiving .

this also isnt a racing condition as this holds true even after 30 seconds …

maybe the window object is global(above router) , but then i cant use window at all.

is window.document global too then ???

this information is also critical when you use firestore with subscribe(); then you may use an array index to input data but firestore already updated the array on the recent page in the background and you write to the wrong array slot …

seriously thinking about porting the app to vanilla js + ionic instead of angular. theres so many pits you can fall into with angular routing , this is the second very huge shortcoming ive come across…

Hi @alexmehler, I’m struggling to follow exactly but what I think you’re saying is you want to bind a window event listener on a page, but only while it’s active?

Then you can bind and unbind it in the lifecycle methods for that page:

import { Component } from '@angular/core';

@Component({
  selector: 'app-scanner',
  templateUrl: 'scanner.page.html',
  styleUrls: ['scanner.page.scss']
})
export class ScannerPage {

  constructor() {}
 
  pressHandler = () => {
  }

  ionViewDidEnter() {
     window.addEventListener('keypress', this.pressHandler);
  }

  ionViewDidLeave() {
    window.removeEventListener('keypress', this.pressHandler);
  }

}

See the lifecycle docs for more info: https://ionicframework.com/docs/angular/lifecycle#ionic-page-events

Does that help?

hello @max thanx, yes that might work but i cant seem to get setTimeOut to run and also this. is not the same if its not an anonymous function …

i now tried to port most of my javascript to angular code but this function , i tried everything and i cannot get it over , it fails always at some point

Three words I get very nervous to see in Angular apps are “window”, “function”, and “setTimeout”. While you wait for better answers, would you be interested in thinking through whether it might be possible to redesign this so that none of those need to be used?

Big picture here, I consider event dispatching and DOM management to be framework territory. When I mess with them directly, I find myself fighting the framework, as you appear to be here. When I work through the framework to do them, I am much happier.

@rapropos @max

thanx both of you i found that i used the wrong strategy. This function would spawn mutiple times after calling the page multiple times.

the solution to this question is to use @HostListener like explained here with keyup or keypress event:

https://angular.io/api/core/HostListener

with the hostlistener you can listen to global events in a specific angular page only … not adding and removing event listeners, this. is passed correctly and the code follows correct class structure.

after this problem, i restructured most of my app into the “angular way”.

EDIT: Important!

following pages of the page where you bind @Hostlistener still call the function ! you must add something like

if (this.router.url != "/monitors") {
      //console.warn("Not on Monitors page ");
      return;
    };

to the top of your function.

if you go back though and the page is destroyed, the listener is gone too and everythings ok.

2 Likes