Mi aplicación Angular2 usa un modal ng-bootstrap para mostrar algunos gráficos de resultados en detalle. Por esta razón, cambié el tamaño del modal a casi pantalla completa (solo margin: 20px quedan 20 px). Esto hace que algunos usuarios usen el botón Atrás del navegador en lugar del botón Cerrar en la parte superior derecha o inferior de la página.
Lo que intento ahora es cancelar el evento de retroceso del navegador predeterminado y cerrar el modal en su lugar cuando se llama al evento.
Estoy usando un código de aquí como código base para escuchar el evento del navegador y lo amplí con algunas cosas:
import { PlatformLocation } from '@angular/common' (...) modalRef: NgbModalRef; constructor(location: PlatformLocation) { location.onPopState(() => { console.log('pressed back!'); // example for a simple check if modal is opened if(this.modalRef !== undefined) { console.log('modal is opened - cancel default browser event and close modal'); // TODO: cancel the default event // close modal this.modalRef.close(); } else { console.log('modal is not opened - default browser event'); } }); } (...) // some code to open the modal and store the reference to this.modalRefEl problema es que no sé cómo y si puedo cancelar el evento de retroceso predeterminado.
location.onPopState((event) => { event.preventDefault(); });Esto en realidad no funciona. Lo mismo para esta solución . ¿Tal vez pueda insertar una pila de historial "falsa" cuando abra el modal?
Para AngularJS 1.x parece que realmente funciona: https://stackoverflow.com/a/33454993/3623608
De hecho, resolví mi problema insertando un estado de historial "falso" cuando abrí el modal. La función para apertura modal y cierre modal se ve así:
modalRef: NgbModalRef; open(content: NgbModal) { this.modalRef = this.modalService.open(content); // push new state to history history.pushState(null, null, 'modalOpened'); this.modalRef.result.then((result) => { this.closeResult = `Closed with: ${result}`; }, (reason) => { this.closeResult = `Dismissed ${this.getDismissReason(reason)}`; }); } private getDismissReason(reason: any): string { // go back in history if the modal is closed normal (ESC, backdrop click, cross click, close click) history.back(); if (reason === ModalDismissReasons.ESC) { return 'by pressing ESC'; } else if (reason === ModalDismissReasons.BACKDROP_CLICK) { return 'by clicking on a backdrop'; } else { return `with: ${reason}`; } }Las funciones open() y getDismissReason() se copian de https://ng-bootstrap.github.io/#/components/modal "Modal con opciones predeterminadas". Las partes importantes que agregué están impulsando el nuevo estado del historial en la apertura modal y retroceden en el historial en el cierre modal "normal". Cuando retrocedemos con el botón Atrás del navegador, esta función no se llama y retrocedemos en el historial automáticamente.
Para asegurarse de que el modal se cierre en el evento de historial anterior, necesita las siguientes líneas:
constructor(private location: PlatformLocation, private modalService: NgbModal) { location.onPopState((event) => { // ensure that modal is opened if(this.modalRef !== undefined) { this.modalRef.close(); } });Conclusión: cuando se abre el modal, empujamos un nuevo estado de historial (por ejemplo, con la página actual). Si el modal se cierra normalmente (usando ESC, botón de cierre, ...) el evento de retroceso del historial se activa manualmente (no queremos apilar estados de historial). Si el navegador activa el evento de retroceso del historial, solo tenemos que cerrar el modal si está abierto. La pila de historial empujada asegura que permanezcamos en la misma página.
Limitaciones: agregar una nueva pila de historial y retroceder en el historial también brinda la oportunidad de avanzar en el historial (después de cerrar el modal). Este no es el comportamiento deseado.
ng-bootstrap modal, ahora tiene dismissAll()
https://ng-bootstrap.github.io/#/components/modal/api#NgbModal
Puede cerrar todos los modales abiertos usando un protector de ruta cuando ng-router detecta un cambio (incluido el retroceso del navegador)
export class NgbModalDismissAllGuard implements CanActivateChild { constructor(private modalService: NgbModal) {} canActivateChild( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> | Promise<boolean> | boolean { if (this.modalService.hasOpenModals()) this.modalService.dismissAll(); return true; } }y en la configuración del enrutador..
const routes: Routes = [ { path: '', canActivateChild: [NgbModalDismissAllGuard], loadChildren: () => import('./Custom.Module').then(m => m.CustomModule) } ];On Destroy Lifecycle hook solucionará su problema.
export class AppComponent implements OnDestroy{ @ViewChild('childModal') childModal :CommonModalComponent; constructor(private viewContainerRef: ViewContainerRef) { } ngOnDestroy() { this.childModal.hide(); } }