Angular 4 router: prevent direct browser navigation
Asked Answered
B

2

7

How can I convince the Angular 4 router to disable direct browser navigation within my app?

I have looked into the router hooks CanActivate and CanDeactivate and implemented them but CanDeactivate does not fire at all when using direct browser navigation.

I can use CanActivate to prevent the url but only after the app reboots, which takes time and undesired changes in the browser window.

I want to be able to catch the direct browser navigation BEFORE the app reboots.

In case this helps: I want to disallow direct browser navigation altogether, so I don't need a solution that allows certain urls and disables others.

Here's my router definition:

const routes: Routes = [
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
  { path: 'dashboard', component: DashboardComponent, canActivate: [RouteGuardService] },
  { path: 'users', component: UsersMainComponent, canActivate: [RouteGuardService] },
  { path: 'vendors', component: VendorMainComponent, canActivate: [RouteGuardService] },
  { path: 'invoices', component: InvoicesMainComponent, canActivate: [RouteGuardService] },
  { path: 'offers' , component: EsdMainComponent, canActivate: [RouteGuardService] },
  { path: 'settings' , component: SettingsMainComponent, canActivate: [RouteGuardService] },
  // Callback MUST not be route guard protected.
  { path: 'callback' , component: CallbackComponent },
  { path: 'createvendor' , component: CreateVendorsComponent, canActivate: [RouteGuardService] },
  { path: 'customerdashboard' , component: CustomerDashboardComponent, canActivate: [RouteGuardService] },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [RouteGuardService]
})
export class AppRoutingModule { }
Bookmark answered 1/8, 2017 at 1:34 Comment(1)
Can you provide your router code?Handcrafted
B
7

The following solution is not an Angular based one. As Maximus explained in his answer this is a browser issue and therefor the solution must be browser based.

This solution is derived from an answer on this site (see here) I have written a little (typescript) service with the following three methods:

  private preventNavigation(): void {
    const location = window.document.location;
    const originalHashValue = location.hash;

    window.setTimeout(() => {
      location.hash = 'preventNavigation' + (9999 * Math.random());
      location.hash = originalHashValue;
    }, 0);
  }

  public disableBrowserNavigation(): void {
    window.addEventListener('beforeunload', this.preventNavigation, false);
    window.addEventListener('unload', this.preventNavigation, false);
  }

  public enableBrowserNavigation(): void {
    window.removeEventListener('beforeunload', this.preventNavigation);
    window.removeEventListener('unload', this.preventNavigation);
  }

This works fine but I'm still open to other solutions.

Bookmark answered 2/8, 2017 at 3:40 Comment(0)
K
3

How can I convince the Angular 4 router to disable direct browser navigation within my app?

Angular can't do that because that's not something controlled by Angular. When you go the address bar and type in address and then press enter a browser loads a new page. It can be an Angular application or can be any other application. It's a browser functionality. Angular controls navigation only inside the app when you click on the routerLink.

You could try to use onbeforeunload but it has its limitations.

Kokanee answered 1/8, 2017 at 4:29 Comment(1)
onbeforeunload by itself doesn't work in my case because of the limitations you mentioned. However, going deeper in that direction has led to a possible solution. I'll check it out and if it works will share it as an answer. I understand and agree with your argument that it is out of Angular's control because it is a browser functionality.Bookmark

© 2022 - 2024 — McMap. All rights reserved.