Aiguo
Aiguo

Reputation: 3566

Execute a method when a user navigates away from a page/route: Angular2

I'm trying to run a function whenever current route is changed. For example, if we are currently on "..../user/user-details", where user-details is a separate component. I want to execute a method whenever the route is changed (shouldn't matter if route changes from the UI or directly from the URL). I did something in the user-details component:

constructor(private router: Router) {
  router.events.subscribe(() => {
    console.log('Route changed');
 });
}

But the issue with this approach is, it runs on every route change (whether or not we are navigating to or from user-details page). So this is subscribing to app wide routes. I just want it to run whenever we are navigating away from user-details component. Is their a way to do that?

Upvotes: 6

Views: 5633

Answers (1)

Teddy Sterne
Teddy Sterne

Reputation: 14221

If you want to just run code when leaving the user-details component then you need to create a CanDeactivate Guard on the route.

Setup the guard so that the UserDetailsComponent implments a interface with a method to call before the route gets deactivated. Then register the CanDeactivate Guard on the route and inside the guard call the method on the route.

interface BeforeUnload {
    beforeunload(): Observable<boolean>|Promise<boolean>|boolean;
}

@Component({ /* ... */})
class UserDetailsComponent implements BeforeUnload {
    beforeUnload() {
        /* ... custom code ... */
        return true;
    }
}

@Injectable()
class CanDeactivateComponent implements CanDeactivate<T extends BeforeUnload> {
  constructor() {}

  canDeactivate(
    component: T,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot,
    nextState: RouterStateSnapshot
  ): Observable<boolean>|Promise<boolean>|boolean {
    return component.beforeUnload();
  }
}

@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: 'user/user-details',
        component: UserDetailsComponent,
        canDeactivate: [CanDeactivateComponent]
      }
    ])
  ],
  providers: [CanDeactivateComponent]
})
class AppModule {}

In this example I set it up so that the route won't leave until the method on the component returns a response but you could immediately return true depending on if beforeUnload is synchronous or not.

Upvotes: 10

Related Questions