简体   繁体   中英

Angular remove locationStrategyListener on ngDestroy

I am wondering why my problem seems to be so non-trivial: As we have implemented server side querying, pagination, etc. we need to request our API whenever the user makes changes in the table (eg when querying for name=x the client sends a request with corresponding query parameters to the backend). This also means that we need to request the backend when going back in history, specifically when clicking the back button of the browser.

This works fine with the following code:

constructor(private locationStrategy: LocationStrategy) { }

ngOnInit() {
    this.locationStrategy.onPopState(() => {
        this.refreshHistory();
    })
}

However, since in every initialization of the component we add a new listener to listen to the history event, we are quickly sending hundreds of equal requests to the backend (since each listener invokes the refreshHistory() method).

I somehow need to remove any eventListener in the ngDestroy interface, but locationStrategy does not seem to provide such a feature. Is there any (clean) way to achieve this?

Thanks in advance!


PS: Please correct me if this is a totally wrong approach. I am more used to implement backends than frontends.

The solution for this is actually pretty easy once one read through the heck of RxJS documentation. We use its fromEvent operator to create a subscription of the onPopState event. From this subscription we can easily unsubscribe and everything works like a charm.

import {fromEvent, Subscription} from "rxjs";

export class CommentAllComponent implements OnInit, OnDestroy {

    private backEvent: Subscription;

    ngOnInit() {
        this.backEvent = fromEvent(window, 'popstate').subscribe(() => {
        // doCustomRefresh()
        });
    }

    ngOnDestroy(): void {
        this.backEvent.unsubscribe();
    }
}

Alternate Approach

Instead of using LocationStrategy, I would suggest that you take a look at using the queryParams of the route. You can subscribe to them in ngOnInit , and unsubscribe in ngOnDestroy . It seems like it would work well in your case where you are basically trying to navigate back to a previous state in a component.

For example a user might click back from here:

localhost:4200/#/table?filterString=foo&colSort=idAscending

And end up here:

localhost:4200/#/table?filterString=foo

export class MyComponent implements OnInit, OnDestroy {
  paramSub: Subscription;
  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    this.paramSub = this.route.queryParams.subscribe(params => {
      console.log(params); // query params changed, getData()
    })
  }

  ngOnDestroy(){
    this.paramSub.unsubscribe();
  }
}

In addition to the angular docs, I found this article helpful for getting started with QueryParams https://alligator.io/angular/query-parameters/

Extra

The problem with LocationStrategy is, as you've noted, there isn't a provided way to remove a listener.

I dont know enough to say whether it's impossible to continue this approach, but it's certainly more complex. You could try using a named function, instead of an anonymous function like so:

  constructor(private location: LocationStrategy) { }

  ngOnInit() {
    this.location.onPopState(this.popStateHandler);
  }

  popStateHandler(event){
    console.log('handle onPopState', event);
  }

It seems like step in the right direction in that it solves the issue of registering a new handler function every time you initialize the component. But then the problem becomes the fact that every time you click back regardless of where you are in the app, the handler function will fire.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM