Angular2 - Prevent ngOnDestroy from happening

2020-06-19 06:13发布

问题:

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;
        }
    }
}

回答1:

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.



回答2:

You would wanna use CanDeactivate. 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 & must return either True or false
    if (this.user.name !== this.editName) {
      return window.confirm('Discard changes?');
    }

    return true;
}

Note: Follow step 1 & 2 only once, obviously, & just repeat step 3 & 4 for every other component where you want the same behaviour, meaning, to prevent ngOnDestroy or in other words, 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