Web Develop Wolf
Web Develop Wolf

Reputation: 6326

Browser Back Button default behavior still executing on stop propigation

I have an angular site in which I've inserted some code to make the browser back button behave in the same way as the back UI button. However when I press back on the browser I get the last visited page flashing for a second before the default behavior executes.

Here's a video to show what I mean - at the end I show the what clicking the UI button does which is what I want to emulate: Browser Back Button Demo

And here's the code I'm using in Angular:

@HostListener('window:popstate', ['$event'])
  onBrowserBackBtnClose(event: Event) {
      // Stop default behavior of the back button
      event.stopPropagation();
      event.preventDefault();
      // If we can go back...
      if (this.canGoBack) {
        // Load the previous question
        this.questionService.previousQuestion().subscribe(res => {
          // Activate the question route in place of the previous page
          this.router.navigate(['question'], {replaceUrl: true});
        });
      }
  }

My understanding was that event.stopPropagation(); and event.preventDefault(); stopped this flickering behavior? Or is there something else I'm not understanding or missing?

Upvotes: 6

Views: 1777

Answers (3)

Andran
Andran

Reputation: 299

My way to fix this issue: I have some element table and I can open each element detail page by click in row. After browser back navigation in detail page I need to scroll and highlight element row in table. For this i need to navigate by fragment(element id)

// if i have fragment
this.backQuery = window.history.state.query;
this.backFragment = window.history.state.fragment;
history.pushState(null, '');

And i need to listen browser back navigation event

@HostListener('window:popstate', ['$event'])
onPopState(event: any): void {
  if (this.backFragment) {
    let query = '';
    if (this.backQuery) {
      Object.keys(this.backQuery).forEach(key => {
        query = query + key + '=' + this.backQuery[key] + '&';
      });
      query = '?' + query.replace(/\&$/g, '');
    }
    window.location.href = `table-page${query}#${this.backFragment}`;
  }
}

Upvotes: 0

Dipen Shah
Dipen Shah

Reputation: 26075

You cannot cancel popstate event in the browser, read more about the event on MDN page. That being said, you can update window history (technically a hack) and push current location again so that page will be navigated back to current page using:

window.history.pushState(null, null, window.location.pathname);

Not sure, how you can apply it to your code as I do not have working demo of your app, but it could look something like:

@HostListener('window:popstate', ['$event'])
onBrowserBackBtnClose(event: Event) {
  // prevent browser from moving to different page
  window.history.pushState(null, null, window.location.pathname);
      
  // If we can go back...
  if (this.canGoBack) {
    // Load the previous question
    this.questionService.previousQuestion().subscribe(res => {
      // Activate the question route in place of the previous page
      this.router.navigate(['question'], {
        replaceUrl: true
      }); // you will need some other code to determine and navigate to next page if user chooses to
    });
  }
}

Upvotes: 0

Timothy
Timothy

Reputation: 3593

If I was you I would rather use native Angular approach here. In this particular case you can implement CanDeactivate or CanActivate Route Guards.

In both of this interfaces methods uses asynchronous returns such as:

Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree

Upvotes: 1

Related Questions