2

How to prevent closing browser tab when form is dirty in Angular 2?

My html body contains a component:

  <body>
    <my-app>Loading, please wait...</my-app>
  </body>

which contains a router navigation and a router outlet:

<nav>
 (...)
</nav>
<router-outlet></router-outlet>

and when the router navigates to the edit page, I have some form there:

  <form #myForm="ngForm">
    <button pButton type="text" label="Save" (click)="onSave()" [disabled]="!myForm.valid || myForm.pristine"></button>
  </form>

Now, if the form is not 'pristine', I want to ask for confirmation when the user tries to close the browser tab:

window.onbeforeunload = function() {
   if (form.dirty) {
     return "You have unsaved data changes. Are you sure to close the page?"
   }
}

How can I access the dirty state of Angular form in canonical way from there? I could register an event to field change on each field and set the global dirty flag, but I'd have to put that code on every from and by every navigation and then maintain that code so that the message stays consistent. Is there any other way to check out if there's an angular form on the page, which is in dirty state?

9ilsdx 9rvj 0lo
  • 7,955
  • 10
  • 38
  • 77

5 Answers5

4

Perhaps

@HostListener('window:beforeunload', ['$event'])
handleBeforeUnload(event) {
  if (connected) {
    return "You have unsaved data changes. Are you sure to close the page?"
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • And I define that @HostListener in every component that has #ngForm that can be dirty? – 9ilsdx 9rvj 0lo Nov 21 '16 at 12:30
  • 1
    Anyway, the @HostListener added to my component is shown gray (unused code) and isn't called when closing windows. – 9ilsdx 9rvj 0lo Nov 21 '16 at 12:41
  • Sorry, you are right. I forgot to add `window:` (see updated question). I don't know about your "shown gray". It's not called directly anyway. – Günter Zöchbauer Nov 21 '16 at 12:45
  • I've tried with window: By show gray, I've meant the behaviour of IDE (WebStorm) which detects the code is unused. Will the @HostListener annotation work on ANY component, or only on some specific components? – 9ilsdx 9rvj 0lo Nov 21 '16 at 12:49
  • `@HostListener()` works on any component. As mentioned I don't think WebStorm showing it as unused means much. It's called in a reflective way. – Günter Zöchbauer Nov 21 '16 at 12:51
  • So bad luck on my site, it's just not working (newest version of Angular2). I've got to throw away your '[$event]' part, because it resulted in runtime error: (System.js args.join is not a function – 9ilsdx 9rvj 0lo Nov 21 '16 at 12:58
  • Sorry again. I had another mistake, The `[]` have to be outside the `''` (haven't used this since a while). I don't think this can be reproduced in Plunker otherwise I'd try to demonstrate it. – Günter Zöchbauer Nov 21 '16 at 13:00
  • Seems I misinterpreted your question a bit. Yes, you can pass a validator to a `FormGroup`. https://angular.io/docs/ts/latest/api/forms/index/FormGroup-class.html shows an example similar to yours. – Günter Zöchbauer Nov 21 '16 at 13:06
1

Add a Hostlistener decorator. If there are unsaved changes on the form confirm dialog appears.

@HostListener('window:beforeunload', ['$event'])
handleBeforeUnload(event: Event) {
    event.returnValue = false;
}
ivaigult
  • 6,198
  • 5
  • 38
  • 66
Pavlo Kozachuk
  • 244
  • 3
  • 7
1

This works. Implement the hasUnsavedData() function accordingly.

  hasUnsavedData(){
    return this.myForm.dirty;
  }

  @HostListener('window:beforeunload', ['$event'])
  handleBeforeUnload($event: any) {
      if (this.hasUnsavedData()) {
          $event.returnValue = true;
      }
  }
Rohit Katariya
  • 119
  • 1
  • 9
-1

Simply you can use Jquery to get state of ng-form.

@HostListener('window:beforeunload', ['$event'])
beforeUnloadHandler(event) {
   if($('form').hasClass('ng-touched')) { //You can check with ng-dirty based on your requirements.
        let confirmMessage = 'You have unsaved data changes. Are you sure to close the page?'
        event.returnValue = confirmMessage;
        return confirmMessage;
   }

}

In my case am just showing warning dialog if that the form has been touched.

Nat4j
  • 453
  • 2
  • 7
  • 19
-1

Try this directive https://github.com/extremeprog-com/ng-prevent-navigation.

So it should be simple

<div ng-prevent-navigation="vm.pageShouldBeReloaded"
     ng-prevent-navigation-text="Payment form has unsaved changes. 
        If you leave the page now you will lose those changes."
></div>
myfoxtail
  • 14
  • 1