Angular 2 How to detect back button press using router and location.go()?

107,464

Solution 1

I don't know if the other answers are dated, but neither of them worked well for me in Angular 7. What I did was add an Angular event listener by importing it into my component:

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

and then listening for popstate on the window object (as Adrian recommended):

  @HostListener('window:popstate', ['$event'])
  onPopState(event) {
    console.log('Back button pressed');
  }

This worked for me.

Solution 2

Another alternative for this issue would be to subscribe to the events emitted by the Angular Router service. Since we are dealing with routing, it seems to me that using Router events makes more sense.

constructor(router: Router) {
    router.events
      .subscribe((event: NavigationStart) => {
        if (event.navigationTrigger === 'popstate') {
          // Perform actions
        }
      });
}

I would like to note that popstate happens when pressing back and forward on the browser. So in order to do this efficiently, you would have to find a way to determine which one is occurring. For me, that was just using the event object of type NavigationStart which gives information about where the user is coming from and where they are going to.

Solution 3

To detect browser back button click import platformlocation from '@angular/common and place the below code in your constructor :

 constructor(location: PlatformLocation) {
     location.onPopState(() => {
        alert(window.location);
     }); }

Solution 4

Angular documentation states directly in PlatformLocation class...

  • This class should not be used directly by an application developer.

I used LocationStrategy in the constructor

constructor(location: LocationStrategy) {
  location.onPopState(() => {
    alert(window.location);
  });
}

Solution 5

A great clean way is to import 'fromEvent' from rxjs and use it this way.

fromEvent(window, 'popstate')
  .subscribe((e) => {
    console.log(e, 'back button');
  });
Share:
107,464

Related videos on Youtube

Adrian Moisa
Author by

Adrian Moisa

Tech Lead, Project Manager, Founder at Qualia Vision

Updated on July 30, 2022

Comments

  • Adrian Moisa
    Adrian Moisa almost 2 years

    I have built an app that uses router 3.0.0-beta.1 to switch between app sections. I also use location.go() to emulate the switch between subsections of the same page. I used <base href="/"> and a few URL rewrite rules in order to redirect all routes to index.html in case of page refresh. This allows the router to receive the requested subsection as a URL param. Basically I have managed to avoid using the HashLocationStrategy.

    routes.ts

    export const routes: RouterConfig = [
        {
            path: '',
            redirectTo: '/catalog',
            pathMatch: 'full'
        },
        {
            path: 'catalog',
            component: CatalogComponent
        },
        {
            path: 'catalog/:topCategory',
            component: CatalogComponent
        },
        {
            path: 'summary',
            component: SummaryComponent
        }
    ];
    

    If I click on a subsection in the navigation bar 2 things happen:

    • logation.go() updates the URL with the necessary string in order to indicate the current subsection
    • A custom scrollTo() animation scrolls the page at the top of the requested subsection.

    If I refresh the page I am using the previously defined route and extract the necessary parameter to restore scroll to the requested subsection.

    this._activatedRoute.params
        .map(params => params['topCategory'])
        .subscribe(topCategory => {
            if (typeof topCategory !== 'undefined' &&
                topCategory !== null
            ) {
                self.UiState.startArrowWasDismised = true;
                self.UiState.selectedTopCategory = topCategory;
            }
        });
    

    All works fine except when I click the back button. If previous page was a different section, the app router behaves as expected. However if the previous page/url was a subsection, the url changes to the previous one, but nothing happens in the UI. How can I detect if the back button was pressed in order to invoke the scrollTo() function to do it's job again?

    Most answers I saw relly on the event onhashchange, but this event does not get fired in my app since I have no hash in the URL afterall...

  • Christophe Gigax
    Christophe Gigax almost 7 years
    The problem with onPopState is that the event is raised even if the user go forward.
  • Raul A.
    Raul A. almost 6 years
    This creates a global listener for the window:popstate event while using @HostListener will only listen when on the current component.
  • Joshua JLIVE Williams
    Joshua JLIVE Williams over 5 years
    how do you stop listening to events or unsubscribe from this event. i tried using fromEvent(window, 'popstate') and unsubscribing there but it didnt work.
  • Ben Taliadoros
    Ben Taliadoros over 5 years
    you could do location.onPopState = () => {}
  • KlavierCat
    KlavierCat about 5 years
    According to Angular's official documentation, PlatformLocation should not be used directly by an application developer.
  • KlavierCat
    KlavierCat about 5 years
    I adopted this solution, much cleaner indeed. I define a subscription, then do the subscribe in ngOnInit, and the unsubscribe in the ngOnDestroy.
  • indrajeet
    indrajeet almost 5 years
    Would this work if I'm using mobile device and pull down the screen and refresh the page?
  • daddywoodland
    daddywoodland over 4 years
    Appreciate the steer on the need for further logic to determine between forward and back
  • Florent Arlandis
    Florent Arlandis over 4 years
    As MDN states: "A popstate event is dispatched to the window each time the active history entry changes between two history entries for the same document". That means the event will be triggered when the user clicks on "back" but also on "forward"
  • Mohammad Kermani
    Mohammad Kermani over 4 years
    This answer looks to provide a better solution
  • Muhammad Bilal
    Muhammad Bilal about 4 years
    @indrajeet /* Handle the tab closed/refreshed event / @HostListener('window:beforeunload', ['$event']) unloadNotification($event: any) { if (pendingTask()) { / Implement your logic that either you have any pending task or not */ return false; } else { return false; } }
  • Sean Halls
    Sean Halls almost 4 years
    "Latest" Angular version doesn't help people who come to the question years later. Would love to have this have stated the actual version you were on.
  • VSO
    VSO almost 4 years
    @SeanHalls We were on 7 at the time. I will update the answer.
  • Mikkel R. Lund
    Mikkel R. Lund about 3 years
    PlatformLocation: "This class should not be used directly by an application developer."
  • matt forsythe
    matt forsythe about 2 years
    If you use this solution, you must also unsubscribe from the router.events observable. Otherwise, once you visit the page with this code, the "perform actions" will continue to execute for every popstate action application wide.