Angular Router Freeze
A better, simpler yet more powerful way to prevent navigation in Angular apps.
npm i ng-router-freeze
Features
In contrast with Angular's built-in CanDeactivate
based setup
- ✅ Super minimal setup, to get navigation blocking just decorate > allow > enable, and you're set!
- ✅ Super DRY. Perhaps TOOOO DRY.
- ✅ Allows even the child components to "deactivate" a route as opposed to just the component set in route config.
- ✅ Integration tested with Angular 8 (6, 7, 9 coming soon)
- 🚧 TODO - Deals with the infamous routing history bug known since 2016!!
Usage
As easy as 1, 2, 3!
1️⃣ First, include the NgRouterFreezeModule
module in the AppModule
:
import { BrowserModule } from '@angular/platform-browser';+ import { NgRouterFreezeModule } from 'ng-router-freeze'; import { AppRoutingModule } from './app-routing.module'; @NgModule({ imports: [ BrowserModule,+ NgRouterFreezeModule, AppRoutingModule ] }) export class AppModule { }
2️⃣ Then, add the navigation blocking logic to components:
// edit-report.component.ts import { Component, OnInit } from '@angular/core';+ import { WithNavigationBlocking, NavigationBlocking } from 'ng-router-freeze'; import { ModalService } from '../services/modal.service'; + @WithNavigationBlocking() @Component({ selector: 'dash-edit-report', templateUrl: `./edit-report.component.html`, styleUrls: ['./edit-report.component.scss'] })- export class EditReportComponent implements OnInit {+ export class EditReportComponent implements OnInit, NavigationBlocking { constructor(private modalService: ModalService) {} ... + canNavigate() {+ return this.isDraftSaved() || this.modalService.confirm('Discard changes?');+ } ... }
3️⃣ Lastly, allow the component(s) to block navigation:
Navigation blocking will not kick in until the component is explicitly allowed for some or all routes in route config
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router';+ import { NavigationGuard, enableNavigationBlocking } from 'ng-router-freeze'; import { ReportService } from './services/report.service'; import { ViewReportComponent } from './components/view-report.component'; import { NewReportComponent } from './components/new-report.component'; import { EditReportComponent } from './components/edit-report.component'; import { ReviewReportComponent } from './components/review-report.component'; export const routes: Routes = [ { path: ':id', data: { title: 'Report' }, component: ViewReportComponent,+ canDeactivate: [NavigationGuard] }, { path: 'new', data: { title: 'New Report' }, component: NewReportComponent,+ canDeactivate: [NavigationGuard] }, ]; + enableNavigationBlocking(routes, [+ { path: ':id', allow: [EditReportComponent, ReviewReportComponent] },+ { path: 'new', allow: [EditReportComponent] }+ ]); @NgModule({ declarations: [ ReportSummaryComponent, NewReportComponent, EditReportComponent, ReviewReportComponent ],+ // works with child routes as well imports: [RouterModule.forRoot(routes)], providers: [ReportService] }) export class AppRoutingModule { }
👏👏 And that's it!
License
Licensed under MIT