16

I want to prevent page refresh by everywhere.

I tried the code below

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { CommonServices } from '../services/common.service'; 

@Component({
  selector: 'app-review-prescription',
  templateUrl: './review-prescription.component.html',
  styleUrls: ['../../assets/css/prescriptionView.css'],
  providers:[
    CommonServices
  ]
})
export class ReviewPrescriptionComponent implements OnInit {
    constructor(
        private commonServices:CommonServices,
        private router:Router
        ){}
    ngOnInit(){
      window.onbeforeunload = function(event) {
        return 'By refreshing this page you may lost all data.';
      }
  }

}

Tried this on ngOnChanges(), ngOnInit(), ngOnDestroy() even outside the component class(sorry illogical) but nothing works?

I need solution in Angular or JavaScript not in jQuery.

Thanks.

RajnishCoder
  • 3,455
  • 6
  • 20
  • 35

8 Answers8

12

Try the below subscription to throw alert window on page refresh. do some user events like click over the page before trying to refresh or close the window. check the working version here

see the official documentation on beforeunload

ngOnInit() {
    window.addEventListener("beforeunload", function (e) {
        var confirmationMessage = "\o/";
        console.log("cond");
        e.returnValue = confirmationMessage;     // Gecko, Trident, Chrome 34+
        return confirmationMessage;              // Gecko, WebKit, Chrome <34
    });
}
SHUMING LU
  • 129
  • 9
Prithivi Raj
  • 2,658
  • 1
  • 19
  • 34
6
@HostListener("window:beforeunload", ["$event"]) unloadHandler(event: Event) {
      event.returnValue = false;
  }
4

The solution depends on why you want to prevent the page reload. If you want to prevent it because there can be unsaved changes you have actually to prevent two different behaviours:

  1. Browser page reload. You can achieve this by creating an HostListener on the beforeunload event (similar to your attempt) like:
    @HostListener('window:beforeunload', ['$event'])
    beforeUnloadHander() {
        // or directly false
        this.allowRedirect;
    }
  1. Angular routing change (if you have routing): to do that you have to use a Deactivation guard on the route you want to lock, there are many ways but the most appreciated is the one that uses an interface implementation:

I. The interface sets up a couple of fields used in the angular guard to check if the we can change the router path:


    import { Observable } from "rxjs";
    import { HostListener } from "@angular/core";

    // see https://scotch.io/courses/routing-angular-2-applications/candeactivate
    // implementing this interface with a component in angular you can implement a candeactivate
    // guard that automatically checks if there is the canDeactivate function and
    // it allows to navigate out of the route or not
    export default interface LockableComponent {
      allowRedirect: boolean;
      canDeactivate(): boolean;
    }

II. Each component has to implement this interface with the method canDeactivate or the allowRedirect field (reusable in the HostListener for the problem #1) and must returning a boolean that indicates if navigation is allowed or not.

III. Create a router guard that checks this component fields for the deactivation:

  canDeactivate(
    component: LockableComponent,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {
    if (
      (component.allowRedirect === false ||
        (component.canDeactivate && !component.canDeactivate()))
    ) {
      // Angular bug! The stack navigation with candeactivate guard
      // messes up all the navigation stack...
      // see here: https://github.com/angular/angular/issues/13586#issuecomment-402250031
      this.location.go(currentState.url);

      if (
        window.confirm("Sure man?")
      ) {
        return true;
      } else {
        return false;
      }
    } else {
      return true;
    }
  }

III. Set the canDeactivate router guard in your module.routing.ts file:

const myRoutes: Routes = [
      {
        path: "locked-route-path",
        component: ComponentThatImplementsLockedInterface,
        canDeactivate: [TheCanDeactivateGuardJustMade]
      }
      //...
]
bertonc96
  • 772
  • 2
  • 13
  • 24
  • 1
    That's the cleanest I see. While it might be a bit overkill for some really easy app, this technique is the one that is the most modular and reusable. – Chax Sep 12 '19 at 14:13
2

You can try this.

@HostListener('window:beforeunload', ['$event'])
beforeunloadHandler(event) {
    alert('By refreshing this page you may lost all data.');
}

Please be sure to include this inside the class.

clemens
  • 16,716
  • 11
  • 50
  • 65
  • 2
    can you provide any example – Runali Feb 07 '18 at 12:36
  • code is provided in the link please refer- https://medium.com/front-end-weekly/angular-how-keep-user-from-lost-his-data-by-accidentally-leaving-the-page-before-submit-4eeb74420f0d – priya_21 Apr 07 '19 at 09:58
1

I have been looking for a perfect solution for this but there was none of them was perfect.

I have created a solution for this and you can see the full code here. Prevent reload without saving

Code example: https://github.com/mukeshsalaria01/angular-show-alert-on-page-reload-without-saving-example

Mukesh Salaria
  • 3,345
  • 1
  • 16
  • 21
0

I have done it using both RouteGuard and pure Javascript code to prevent browser close tab/back/close window.

Component:

profileForm = this.fb.group({
  ClientName: ['', [Validators.required]]
});

@HostListener('window:beforeunload', ['$event']) beforeUnloadHander(event: any) {
     debugger
     var isFormDirty = document.getElementById('profileformStatus').innerText;
     console.log(isFormDirty);
     if(isFormDirty == 'true'){
       return false;
     }
     else{
       return true;
     }
   }

Component HTML:

<div id="profileformStatus">{{profileForm.dirty ? true:false}}</div>

Your Component Guard Service File(Optional):

import { CanDeactivate } from "@angular/router";
import { Injectable } from "@angular/core";
import { YourComponent } from "./projects/your-component";
@Injectable()

export class YourComponentCanDeactivateGuardService
    implements CanDeactivate<YourComponent> {

    canDeactivate(component: YourComponent): boolean {
        if (component.profileForm.dirty) {
            return confirm('Are you sure you want to discard your changes?');
        }
        return true;
    }
}

Your Module: add The Above Guard(Optional)

@NgModule({
    providers: [YourComponentCanDeactivateGuardService]
})

Finally

Update your routing module(Optional):

const routes: Routes = [
    {
        path: 'detail/:id',
        component: YourComponent,
        canDeactivate: [YourComponentCanDeactivateGuardService]
    }
];

Done. Now it will prevent reload/back navigation both.

Bimal Das
  • 1,882
  • 5
  • 28
  • 53
0

All the previous answers contains this code, but we need to add a statement to prevent the default behaviour.

event.preventDefault()

@HostListener("window:beforeunload", ["$event"])
unloadHandler(event) {
    event.preventDefault();
    return event.returnValue = "Are you sure you want to exit?";
}
-2

For this, you should create a Guard.

in your routing configuration file:

const routes: Routes = [
    {
        path: '',
        redirectTo: '/homePage',
        pathMatch: 'full'
    },
    {
        path: 'accueil',
        component: AccueilComponent,
        canDeactivate: [GuardName]
    }]

By doing this you're calling your guard on the selected component

More informations Here

In your guard:

@Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
  canDeactivate(component: CanComponentDeactivate) {
    return true/false;
  }
}
Terry Pitz
  • 83
  • 7