iPaul
iPaul

Reputation: 433

How to prompt user when leaving the Angular 4 page if there are any changes made?

I have two tabs (PrimeNg Tabview) in my Angular4 page with many input fields like textboxes, textareas, dropdowns etc. I also have a side menu-bar to navigate to other pages within the application. I want if there is any changes in the data in the in those input fields then there will be a pop-up message (a modal or a confirmation box) if user tries to change the tab, or to navigate to other pages using the side menu-bar.

I have tried the ngOnDestroy() method. Though this method gets triggered only when the page is getting closed (by navigating to other page or move to next tab-page) but it is not allowing you show a modal/confirmation box from within the method because it is on destroy life cycle hook.

Please help me to identify the actual event using which I can prompt user with a confirmation box if changes are there in any of the input fields in the page/form.

@surjit Suggestion:

my-guard.service.ts:

export interface CanComponentDeactivate {
    CanDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable()
export class CreateRequestGuardService implements CanDeactivate<CanComponentDeactivate> {
    canDeactivate(component: CanComponentDeactivate) {
        let vDeactivate = component.CanDeactivate ? component.CanDeactivate() : true;
        return vDeactivate;
    }   
}

Inside my-component.ts:

import { CreateRequestGuardService } from './my-guard.service';

canDeactivate(): Observable<boolean> | boolean {
    console.log('I am moving away!');
    if (!this.isSaved) {
        const confirmation = window.confirm('Are you sure?');
        return Observable.of(confirmation);
    }
    else{
        return true;
    }
}

In my-router.ts:

import { CreateRequestGuardService } from './my-guard.service';

const allRoutes: Routes = [
   { path: 'save', component: my-component, canDeactivate: [MyGuardService]},
   { path ....},
   ..
]

Upvotes: 3

Views: 7830

Answers (1)

surjit
surjit

Reputation: 348

Use CanDeactivate guard in the component route which you want to protect

Read CanDeactivate for more information

Update: This is my pseudocode code. It's not tested

my-guard.service.ts:

export interface CanComponentDeactivate {
    CanDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable()
export class CreateRequestGuardService implements CanDeactivate<CanComponentDeactivate> {
    canDeactivate(component: CanComponentDeactivate, 
                  currentRoute: ActivatedRouteSnapshot, 
                  currentState: RouterStateSnapshot, 
                  nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
        return component.canDeactivate(); //the function will be called on the component, that's why we'll implement the function on the component.
    }   
}

my-router.ts:

import { CreateRequestGuardService } from './my-guard.service'; //the class name in my-guard.service.ts

const allRoutes: Routes = [
   { path: 'save', component: myComponent, canDeactivate: [CreateRequestGuardService]},
   { path ....},
   ..
]

my-component.ts

import { CreateRequestGuardService } from './my-guard.service';

export class myComponent implements CanComponentDeactivate { //implements the interface created on the guard service

    /*
        your component data
    */
    //implementation of canDeactivate
    canDeactivate(): Observable<boolean> | Promise<boolean> | boolean {
        if(form_is_edited && not_saved){
            return confirm("Discard Changes?");
        }
        else
            return true;
    }
}

NOTE : Also don't forget to add the guard service(class) to the providers array in the app.module.ts file.

Upvotes: 6

Related Questions