Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 - Prevent ngOnDestroy from happening

I have a page that has a form that checks if the user has unsaved changes before navigating away from it.

The problem is that even with a preventDefault() and return false, the user is still able to click away from the component.

Is there a way to prevent the ngOnDestroy or click event from happening?

Note: User is not going to a different route, just another tab from the same component.

ngOnDestroy() {
    if (this.myForm.dirty) {
        let save = confirm('You are about to leave the page with unsaved changes. Do you want to continue?');
        if (!save) {
            window.event.preventDefault();
            return false;
        }
    }
}
like image 252
franco Avatar asked Jul 11 '17 07:07

franco


2 Answers

You would wanna use CanDeactivate guard.
Here is an example:

1. Create a guard service/provider.

import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';

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

@Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {

  canDeactivate(component: CanComponentDeactivate) {
    return component.canDeactivate ? component.canDeactivate() : true;
  }

}

2. Add your guard service (CanDeactivateGuard) in your app.module providers

providers: [
    CanDeactivateGuard,
]

3. Update your routing, to something like this:

{
    path: "pipeline/:id",
    component: OnePipelineComponent,
    canDeactivate: [CanDeactivateGuard],
  },

4. Implement canDeactivate method in your component where you want to prevent ngOnDestroy. In my case, it was OnePipelineComponent as mentioned in the route above.

canDeactivate() {
    console.log('i am navigating away');

    // you logic goes here, whatever that may be 
    // and it must return either True or False
    if (this.user.name !== this.editName) {
      return window.confirm('Discard changes?');
    }

    return true;
}

Note: Follow steps 1 & 2 only once, obviously, & just repeat steps 3 & 4 for every other component where you want the same behaviour, meaning, to prevent ngOnDestroy or to do something before a component can be destroyed).

Check out these articles for code sample & an explanation for the code written above. CanDeactivate & CanDeactivate Guard Example

like image 113
Junaid Avatar answered Sep 21 '22 16:09

Junaid


You are mixing two concepts - navigating away means to a new route. The correct angular solution to this is implementing a CanDeactivateGuard. The docs on that are here.

A stack overflow question with answers is here.

In your situation the user is not navigating to a new page (ie. the route does not change). They are simply clicking on a new tab.

Without seeing more code, it's hard to know if both tabs are part of the same form or in two different forms.

But regardless, you need a click handler on the other tab button and in THAT click handler you need to check if the data for the current tab is unsaved (ie. if that tab is one single form, is that form dirty?).

So basically move the code you posted from ngOnDestroy and into that click handler.

like image 32
rmcsharry Avatar answered Sep 21 '22 16:09

rmcsharry