Angular 4 router: prevent direct browser navigatio

2019-04-06 22:20发布

问题:

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 { }

回答1:

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.



回答2:

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.