can-deactivate.guard.ts
import {Injectable} from '@angular/core'; import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, CanDeactivate} from '@angular/router'; import {Observable} from 'rxjs/Observable'; export interface CanComponenDeactive { canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean; } @Injectable({ providedIn: 'root' }) export class CanDeactivateGuard implements CanDeactivate<CanComponenDeactive> { canDeactivate(component: CanComponenDeactive, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean { return component.canDeactivate(); } }
edit-server.component.ts
import {Component, OnInit} from '@angular/core'; import {ServersService} from '../servers.service'; import {ActivatedRoute, Params, Router} from '@angular/router'; import {CanComponenDeactive} from '../../can-deactivate.guard'; import {Observable} from 'rxjs/Observable'; @Component({ selector: 'app-edit-server', templateUrl: './edit-server.component.html', styleUrls: ['./edit-server.component.css'] }) export class EditServerComponent implements OnInit, CanComponenDeactive { server: { id: number, name: string, status: string }; serverName = ''; serverStatus = ''; allowEdit = false; changesSaved = false; constructor(private serversService: ServersService, private route: ActivatedRoute, private router: Router) { } ngOnInit() { // retrieve params on initializing this.allowEdit = this.route.snapshot.queryParams['allowEdit'] === '1' ? true : false; console.log(this.route.snapshot.fragment); // retrieve params on changes this.route.queryParams.subscribe((value: Params) => { this.allowEdit = value['allowEdit'] === '1' ? true : false; }); this.route.fragment.subscribe((value: string) => { console.log(value); }); const id = +this.route.snapshot.params['id']; this.server = this.serversService.getServer(id); this.route.params.subscribe((value: Params) => { this.server = this.serversService.getServer(+value['id']); }); this.serverName = this.server.name; this.serverStatus = this.server.status; } onUpdateServer() { this.serversService.updateServer(this.server.id, {name: this.serverName, status: this.serverStatus}); this.changesSaved = true; this.router.navigate(['../'], {relativeTo: this.route}); } canDeactivate(): boolean | Observable<boolean> | Promise<boolean> { if (!this.allowEdit) { return true; } if ((this.serverName !== this.server.name || this.serverStatus !== this.server.status) && !this.changesSaved) { return confirm('Do you want to discard the changes?'); } { return true; } } }
app.module.ts
import {BrowserModule} from '@angular/platform-browser'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {HttpModule} from '@angular/http'; import {AppComponent} from './app.component'; import {HomeComponent} from './home/home.component'; import {UsersComponent} from './users/users.component'; import {ServersComponent} from './servers/servers.component'; import {UserComponent} from './users/user/user.component'; import {EditServerComponent} from './servers/edit-server/edit-server.component'; import {ServerComponent} from './servers/server/server.component'; import {ServersService} from './servers/servers.service'; import {RouterModule, Routes} from '@angular/router'; import {PageNotFoundComponent} from './page-not-found/page-not-found.component'; import {AuthService} from './auth.service'; import {AuthGuard} from './auth.guard'; import {CanDeactivateGuard} from './can-deactivate.guard'; const appRoutes: Routes = [ {path: '', component: HomeComponent}, { path: 'users', component: UsersComponent, children: [ {path: ':id/:name', component: UserComponent}] }, { path: 'servers', canActivateChild: [AuthGuard], component: ServersComponent, children: [ {path: ':id', component: ServerComponent}, {path: ':id/edit', component: EditServerComponent, canDeactivate: [CanDeactivateGuard]} ] }, {path: 'not-found', component: PageNotFoundComponent}, {path: '**', redirectTo: '/not-found'}, ]; @NgModule({ declarations: [ AppComponent, HomeComponent, UsersComponent, ServersComponent, UserComponent, EditServerComponent, ServerComponent, PageNotFoundComponent ], imports: [ BrowserModule, FormsModule, HttpModule, RouterModule.forRoot(appRoutes) ], providers: [ServersService, AuthGuard, AuthService, CanDeactivateGuard], bootstrap: [AppComponent] }) export class AppModule { }
References
https://angular.io/guide/router#candeactivate-handling-unsaved-changes