ngBootstrap

<< Font Awesome Google Auth >>

Bootstrap es un conocido framework CSS/JavaScript para crear páginas web responsive. El código de Bootstrap está escrito en JavaScript puro, pero existe una librería de componentes y directivas Angular que sustituye a la librería original y se llama ng-bootstrap.

En este ejemplo, veremos cómo mostrar una ventana modal que le pregunta al usuario si desea abandonar la página actual. Tendrá 2 botones (sí, no) y la respuesta (verdadero/falso) se devuelve en una promesa. Combinaremos esto con nuestro guard CanDeactivate (recuerda que puede devolver un booleano, una Promise<boolean> o un Observable).

Primero instalamos la librería (puede que necesites actualizar con npm update o ng update primero). Borra también el CSS de bootstrap si lo tenías importado en el archivo angular.json, ya que el comando lo añade automáticamente y quedaría duplicado.

ng add @ng-bootstrap/ng-bootstrap

Ahora, vamos a mostrar una ventana modal en la página de agregar producto (product/add) cuando el usuario intenta abandonar esa página. Hasta ahora, hemos utilizado un cuadro de diálogo de confirmación nativo, pero esta no es una solución ideal.

Primero, necesitamos crear un componente que representará nuestro contenido modal. En este caso, vamos a crear un cuadro de diálogo de confirmación genérico (con botones de sí y no).

ng g component shared/modals/confirm-modal

En la clase del componente, añadiremos 2 propiedades cuyo valor le pasaremos al crear la modal, el título de la modal y el texto del cuerpo. También inyectaremos el servicio NgbActiveModal (en una propiedad pública) que representa el objeto de la ventana modal actual y nos permitirá entre otras cosas, cerrarla.

<div class="modal-header">
  <h4 class="modal-title">{{title}}</h4>
  <button type="button" class="btn-close" aria-label="Close"
    (click)="activeModal.dismiss()"></button>
</div>
<div class="modal-body">
  <p>{{body}}</p>
</div>
<div class="modal-footer">
  <button type="button" class="btn btn-success"
          (click)="activeModal.close(true)">Yes</button>
  <button type="button" class="btn btn-danger"
          (click)="activeModal.close(false)">No</button>
</div>

El método dismiss cierra la ventana cancelando la respuesta, igual que si pulsamos fuera de la venta, mientras que con close, la cerramos con normalidad y podemos devolver un valor. En este caso el booleano indicando si el usuario ha respondído sí o no.

Para abrir la ventana modal, debemos inyectar el servicio NgbModal en el componente donde queramos mostrarla. La ventana modal tiene una propiedad (result), que contiene una promesa con el resultado que devuelva la ventana modal cuando se cierre.

En nuestro caso, como la usamos en el método canDeactivate que usa el correpondiente guard, simplemente devolveremos la promesa de la ventana modal, ya que esta contendrá el booleano correspondiente en función del botón accionado. En el caso de cancelar (dismiss), la promesa se rechaza, por lo que capturamos el error y devolvemos falso en ese caso.

export class ProductFormComponent implements CanComponentDeactivate {
  //...
  #modalService = inject(NgbModal);

  addForm = viewChild.required<NgForm>();
  //...
  canDeactivate() {
    if (this.saved || this.addForm().pristine) {
      return true;
    }
    const modalRef = this.#modalService.open(ConfirmModalComponent);
    modalRef.componentInstance.title = 'Changes not saved';
    modalRef.componentInstance.body = 'Do you want to leave the page?';
    return modalRef.result.catch(() => false);
  }
  //...
}

<< Font Awesome Google Auth >>