Angular Guards: More than Security

Austin
2 min readMay 22, 2017

--

Angular Router has this awesome feature called Route Guards. They let us stop a route transition. One of the most common use cases for a feature like this would be preventing unauthorized users from accessing a page with permissions checking.

While that is an awesome use case, there is a number of use cases that this can be helpful for too. One use case I use guards for is preventing a user from navigating away from a page if they made changes to a form and didn’t save. For this, we want to look at the CanDeactivate guard.

Let’s get started by defining an interface for our component to implement:

export interface ComponentCanDeactivate {
canDeactivate: () => boolean | Observable<boolean>;
}

now in our component we implement this interface like so:

@Component({
selector: 'my-app',
template: `
<h1>Whats your name?</h1>
<input type="text" (change)="isDirty = true" />
`
})
export class App implements ComponentCanDeactivate {
isDirty: boolean = false;
canDeactivate(): boolean {
return !this.isDirty;
}
}

in this component we have a simple form that sets the isDirty flag to true when the input value changes. Next we implement the ComponentCanDeactivate method in our component that will return a boolean whether we can transition to the next page.

Ok now that we have a interface and a component that know how to tell us if they are dirty, lets implement the guard.

import { CanDeactivate } from '@angular/router';export class PendingChangesGuard implements CanDeactivate<ComponentCanDeactivate> {
canDeactivate(component: ComponentCanDeactivate): boolean | Observable<boolean> {
if(component.canDeactivate()) {
return true;
} else {
confirm('You have unsaved changes. Press Cancel to go back and save these changes, or OK to lose these changes.');
}
}
}

In the guard, we get a reference to the component and invoke our newly created canDeactivate method. If the value returns false, we will prompt the user with a confirm box. Pretty slick, eh?

Next, what if a user refreshes the browser? Our router guard won’t prevent against that. To fix this, let’s add a HostListener to listen for the window’s beforeunload.

@Component({
selector: 'my-app',
template: `
<h1>Whats your name?</h1>
<input type="text" (change)="isDirty = true" />
`
})
export class App implements ComponentCanDeactivate {
isDirty: boolean = false;
@HostListener('window:beforeunload')
canDeactivate(): boolean {
return !this.isDirty;
}
}

Pretty sweet huh? Special thanks to this StackOverflow post that helped me write this article!

I’m #ngPanda

I hope you enjoyed the post, if you liked it follow me on Twitter and Github for more JavaScript tips/opinions/projects/articles/etc!

--

--

Austin

Crafter of Software • Lover of #JavaScript #goldendoodles & #opensource