Create a Guard in Angular to Handle Navigation Away from a Component with Unsaved Changes
Tags: angular, router, guard, openai
Published: 2023-02-09 09:53:07

---
title: "Create a Guard in Angular to Handle Navigation Away from a Component with Unsaved Changes"
published: true
description: In this post, we will explore how to create a guard in Angular to handle navigation away from a component with unsaved changes. This guard can be added to the router to prevent accidental loss of data.
tags: Angular, Router, Guard, OpenAI
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-02-09 14:59 +0000
---

*Have you ever found yourself in a situation where you are about to leave a component and want to prevent navigation away from the component if there are unsaved changes? The solution to this issue is to create a guard in Angular that can handle navigation away from a component with unsaved changes. In this blog post, we will look at how to create a guard in Angular that uses an observable value and can be used in the router to handle navigation away from a component with unsaved changes.*

### TLDR: 
> In this blog post, we will create a guard in Angular which uses an observable value and can be used in the router to handle navigation away from a component with unsaved changes. We will also create an interface that components can implement to provide the guard with the necessary information it needs to determine if navigation should be blocked.


## Introduction
When a user navigates away from a component, there could be situations where they have made some changes to the component, and these changes have not been saved. To prevent the loss of these changes, it's best to prompt the user to save these changes or lose them before navigating away from the component. To achieve this, we can create a guard in Angular that will handle the navigation away from the component.



## Creating the Guard
To create the guard, we need to create a class that implements the `CanDeactivate` interface from the `@angular/router` package. The class will have a method `canDeactivate`, which will receive the component that the guard is protecting, the `ActivatedRouteSnapshot`, and the `RouterStateSnapshot`. The method will return a boolean or an observable of a boolean, indicating whether navigation away from the component should be allowed.

```Typescript
import { ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot } from '@angular/router';
import { Observable, take } from 'rxjs';

import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class CanDeactivateBlockNavigationIfChange<T extends BlockNavigationIfChange> implements CanDeactivate<T> {
  canDeactivate(component: T, route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
    return new Observable<boolean>((observer) => {
      component.hasChanges$.pipe(take(1)).subscribe((hasChanges: boolean) => {
        const result = hasChanges ? confirm('You have changes which will be lost') : true;
        observer.next(result);
        observer.complete();
      });
    });
  }
}
```

## Creating the Interface
We also need to create an interface that components can implement to provide the guard with the necessary information it needs to determine if navigation should be blocked. The interface will define an observable property called `hasChanges$`, which will indicate whether there are unsaved changes in the component.

```Typescript
export interface BlockNavigationIfChange {
  hasChanges$: Observable<boolean>;
}
```

## Using the guard in the routing module

In the routing module, you can use the guard by adding it as a property in the route configuration for the component it should protect. To use the guard, you need to import it from the file you defined it in, and then add it to the canDeactivate property in the route configuration.

```Typescript
import { CanDeactivateBlockNavigationIfChange } from './guards/block-navigation-if-change.guard.ts';

const routes: Routes = [
  {
    path: 'edit',
    component: EditComponent,
    canDeactivate: [CanDeactivateBlockNavigationIfChange]
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
```


To use the guard in a component, you need to implement the `BlockNavigationIfChange` interface, and provide an `Observable` which emits the current state of the component's unsaved changes. In this example, we will create an `EditComponent` which implements this interface.


```Typescript
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { Subject } from 'rxjs';

import { BlockNavigationIfChange } from './can-deactivate-block-navigation-if-change.guard.ts';

@Component({
  selector: 'app-edit',
  template: `
    <form [formGroup]="editForm">
      <input type="text" formControlName="name">
    </form>
  `,
})
export class EditComponent implements OnInit, BlockNavigationIfChange {
  editForm = new FormGroup({
    name: new FormControl('')
  });
  hasChanges$ = new Subject<boolean>();

  ngOnInit(): void {
    this.editForm.valueChanges.subscribe(() => {
      this.hasChanges$.next(this.editForm.dirty);
    });
  }
}


```

The `EditComponent` implements the `BlockNavigationIfChange` interface, which means that it must have a property called `hasChanges$` of type `Observable<boolean>`. The component will then subscribe to changes in the form, and if the form becomes dirty, it will use the `.next()` method to emit a new value to the `hasChanges$` subject, which will trigger an update in the guard. This allows the guard to stay updated with the latest changes made to the form and make an informed decision on whether navigation away from the form should be blocked or not.

## How will it seem to the user?
When the user navigates to the `EditComponent`, the guard `CanDeactivateBlockNavigationIfChange` will be activated and start monitoring the form for changes. If the user makes any changes to the form and then tries to navigate away from the component, the guard will check the hasChanges$ subject and see if there are any pending changes. If there are changes, the guard will present a confirmation prompt to the user asking them if they are sure they want to leave the page and lose the changes.

This experience provides a seamless and intuitive way for the user to understand when they have unsaved changes and protects their data by preventing accidental navigation away from the page. The guard allows the user to either stay on the page and continue making changes, or confirm that they want to leave and discard the changes. This experience ensures that the user is always in control of their data and reduces the risk of losing any important information.

## Conclusion

By using the `CanDeactivate` interface and the `Observable` type, you can create a guard in Angular which can be used in your router to handle navigation away from a component which has unsaved changes. This is a useful pattern for preventing the loss of data when a user navigates away from a component.

> Disclaimer: This blog was generated using [OpenAI](https://chat.openai.com/chat) chat robot, guided by [Netsi1964](https://dev.to/netsi1964) and with a few edits by him.