DEV Community

Cover image for Angular 15: Transitioning deprecated CanDeactivate() to Functional Guards
jun
jun

Posted on • Updated on

Angular 15: Transitioning deprecated CanDeactivate() to Functional Guards

As developers, we often find ourselves adapting to changes in the tools and frameworks we use. Recently, while working on my Angular project, I stumbled upon a significant shift in Angular 15: the deprecation of class-based route guards like CanDeactivate(). In their place, Angular has introduced functional guards, providing a more modern and flexible approach to managing route deactivation. In this article, I'll guide you through this transition and share how you can smoothly update your codebase. ✨

Understanding the Change

In previous Angular versions, we used the CanDeactivate() guard to handle route deactivation, implementing custom logic to determine whether a user could leave a particular route. However, Angular 15 introduces functional guards as the new way forward. This change aligns with Angular's mission to simplify and enhance the development experience.

Transitioning to Functional Guards

1) Create a Functional Guard: Start by creating a TypeScript function as your functional guard. This function should return true to allow deactivation or false to prevent it.

export const hasUnsavedChangesGuard: CanDeactivateFn<ComponentCanDeactivate> = (component: ComponentCanDeactivate): Observable<boolean> => {
   if (component.canDeactivate && component.canDeactivate()) {
      return true;
    }
   if (!component.confirm()) {
      return confirm('Are you sure you want to leave this page? If you do, any unsaved changes will be lost.');
    }
}
Enter fullscreen mode Exit fullscreen mode

2) Implement the Functional Guard: In your routing configuration, specify the functional guard for a route.

const routes: Routes = [
  {
    path: 'my-component',
    component: MyComponent,
    canDeactivate: [hasUnsavedChangesGuard],
  },
];
Enter fullscreen mode Exit fullscreen mode

Alternatively, you can use an injectable class as a functional guard by leveraging the inject function. This approach keeps your guard logic separate from your routing configuration, especially for the case you have your custom component such as Dialog component.

const routes: Routes = [
  {
    path: 'my-component',
    component: MyComponent,
    canDeactivate: [() => inject(hasUnsavedChangesGuard).canDeactivate()]
  },
];
Enter fullscreen mode Exit fullscreen mode

Conclusion

By embracing this change in Angular 15, you'll find your route guard implementation becomes more streamlined and adaptable. For detailed examples and additional information, refer to the official Angular documentation.

Change in the development world is inevitable, and adapting to it is key to staying at the forefront of technology. As I worked through this transition in Angular 15, I found it not only improved the development experience but also reinforced the idea that growth and improvement are constants in the world of software development. Embrace these changes, and you'll continue to build better, more maintainable applications πŸ˜„πŸš€

Top comments (8)

Collapse
 
peter_boos_2208749504d3e8 profile image
Peter Boos

So i'm upgrading from 15 to 18.. and its still deprecated ?
Why is the Angular community (google) so in love with deprecating instead of having things done multiple ways, each time a new design ideas comes out, they push anyone to follow it.
This isn't nice if you do large projects, and have to keep up with their avantgarde design goals.

If they deprecate and it is really needed (which i doubt a bit in this case), then say after date X we stop this functionality.. though that would alert people and they don't want to upset the public and run their language as if it was a fashion show.

Collapse
 
junlow profile image
jun

Hey Peter, when I wrote the post, it was happened when I upgrade to v15 last year. After v15, you should refer to the latest official documentation: angular.dev/api/router/CanDeactivate.

Collapse
 
rahuldubeyme profile image
Rahul Dubey

getting no output whenever ng serve cmd run on terminal.

Collapse
 
junlow profile image
jun • Edited

Hi Rahul, there could be various factors on whether deactivation is permitted. I've updated the post with guard and component logic examples. Also, You may check if you've correctly passed your guard in the module's providers (app.module.ts).

Here is the guide with application example from angular docs. I hope it helps.

Collapse
 
rahuldubeyme profile image
Rahul Dubey • Edited

Image description

here is screenshot!
this cmd didn't through any error dunring ng server runs command. and not starting this project.

Thread Thread
 
junlow profile image
jun

It seems you're using a different Angular version and don't seem to be related to this article. Check out the link in my last reply about the application guide a look or just go ahead npm install again.

Collapse
 
vijayhyadav profile image
Vijay.H.Yadav

Hello,
Could please share unit test for above code ?
Thanks in advance.

Collapse
 
junlow profile image
jun

You can simply create a mock component has a canDeactivate method and ensure it works correctly :)