⚙️ Simplifying Navigation Error Handling with Angular’s Upcoming Feature⚙️

Map

You can read this article on Medium as well if you wish!

Angular is set to introduce a new navigation error handler feature, allowing developers to create more robust applications and handle navigation errors easier with more ergonomic API🤗.

Legacy navigation handler

Previously, in order to handle NavigationError developers had to manually subscribe to the router’s events, and then filter the results to capture only navigation errors 🤦‍♂️. On example of such implementation is often seen right in AppComponent:

export class AppComponent implements OnInit {
  // alternatively you could use contsructor injection
  private readonly _router = inject(Router);

  // Legacy approach that will be deprecated soon
  ngOnInit() {
    this._router.events
      .pipe(filter((event) => event instanceof NavigationError))
      .subscribe(() =>
        // Handling NavigationError, e.g. redirect to error route
        this._router.navigate(["error"], { skipLocationChange: true })
      );
  }
}

You can find full stackblitz example here. Trying to access Home route will produce NavigationError. GL HF!

This manual process had following drawbacks:

  • Manual process was time-consuming and prone to errors 🤔
  • Required more setup ⚙️
  • Cluttered component/module with unrelated logic 🔐
  • Required more knowledge increasing learning curve for new developers 📈

New Era

The new feature, enabled through the withNavigationErrorHandler function, provides developers with more ergonomic way to tackle this problems.

The idea behind it according to angular core team:

withErrorHandler is a close replacement for the
RouterModule.forRoot.errorHandler / Router.errorHandler.
It provides a quick, short way for users to define a function to handle
NavigationError events. — angular source code

See below is a basic example how you can use it in your **standalone** application:

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(
      appRoutes,

      // new API goes here!!!
      withNavigationErrorHandler((err: NavigationError) =>
        inject(NavErrorHandler).handle(err)
      )
    ),
  ],
});

The main benefit of this new feature is that it offers developers an easier, more ergonomic and more reliable way of handling navigation errors 🔐.

As you can see, the new feature can leverage the inject function 💉, which is possible due to the fact that under the hood withNavigationErrorHandler utilizes the EnvironmentInjector.runInContext API 💻.

Source code with my comments for **withNavigationErrorHandler** looks like this:

export function withNavigationErrorHandler(
  fn: (error: NavigationError) => void
): NavigationErrorHandlerFeature {
  const providers = [
    {
      provide: ENVIRONMENT_INITIALIZER,
      multi: true,
      useValue: () => {
        const injector = inject(EnvironmentInjector);

        // takes responsibility to react to specific RouterEvent: NavigationError
        inject(Router).events.subscribe((e) => {
          if (e instanceof NavigationError) {
            // enables to use inject function in withNavigationErrorHandler
            injector.runInContext(() => fn(e));
          }
        });
      },
    },
  ];
  return routerFeature(
    RouterFeatureKind.NavigationErrorHandlerFeature,
    providers
  );
}

From the source code above you can see that it affectively performs the same thing we used to do in a past but now performing the heavylifting itself letting us to write less boilerplate code, and avoid some rxjs pitfalls along the way.

Conclusion

Map

The new feature is part of the Angular development team’s ongoing efforts to provide developers with better tools to create more robust and easy to design applications 📊. It provides developers with an easier and more ergonomic way of handling navigation errors 🚀!