Skip to content

Instantly share code, notes, and snippets.

@forfrossen
Forked from whisher/confirm-module.ts
Created October 2, 2018 07:22
Show Gist options
  • Save forfrossen/ac7d6552b61594e6df75a9dfb247a866 to your computer and use it in GitHub Desktop.
Save forfrossen/ac7d6552b61594e6df75a9dfb247a866 to your computer and use it in GitHub Desktop.
How to create a reusable service allowing to open a confirmation modal to use with canDeactivate using ng-bootstrap
/*
Credit to: https://gist.github.com/jnizet/15c7a0ab4188c9ce6c79ca9840c71c4e
Credit to: Giuseppe Luca Lo Re
*/
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Component, Injectable, Directive, TemplateRef } from '@angular/core';
import { NgbModal, NgbModalRef, NgbModalOptions } from '@ng-bootstrap/ng-bootstrap';
/**
* The guarded Component should implement this interface
*/
export interface IsPristineAware {
isPristine(): boolean;
}
/**
* Guard to use with the guarded Component
* component: GuardedComponent,
* canActivate: [IsPristineGuard],
**/
@Injectable()
export class IsPristineGuard implements CanDeactivate<IsPristineAware> {
constructor(private confirmService: ConfirmService) {}
canDeactivate(component: IsPristineAware): Promise<boolean> {
if (!component.isPristine()) {
return this.confirmService.confirm({ title:'Confirm', message: 'Are you sure you want to leave?' });
}
return Promise.resolve(true);
}
}
/**
* Options passed when opening a confirmation modal
*/
interface ConfirmOptions {
/**
* The title of the confirmation modal
*/
title: string,
/**
* The message in the confirmation modal
*/
message: string
}
/**
* An internal service allowing to access, from the confirm modal component,
* the options and the modal reference.
*/
@Injectable()
export class ConfirmState {
/**
* The last options passed ConfirmService.confirm()
*/
options: ConfirmOptions;
/**
* The last opened confirmation modal
*/
modal: NgbModalRef;
}
/**
* A confirmation service, allowing to open a confirmation modal from anywhere and get back a promise.
*/
@Injectable()
export class ConfirmService {
constructor(private modalService: NgbModal, private state: ConfirmState) {}
/**
* Opens a confirmation modal
* @param options the options for the modal (title and message)
* @returns {Promise<boolean>} a promise that is fulfilled when the user chooses to confirm
* or closes the modal
*/
confirm(options: ConfirmOptions): Promise<boolean> {
this.state.options = options;
this.state.modal = this.modalService.open(UIConfirmComponent, { size: 'sm' });
return this.state.modal.result;
}
}
/**
* The component displayed in the confirmation modal opened by the ConfirmService.
*/
@Component({
selector: 'ui-confirm',
template: `<div class="modal-header">
<h4 class="modal-title">
{{ options.title}}
</h4>
<button type="button" class="close" aria-label="Close" (click)="no()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>{{ options.message }}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" (click)="yes()">Yes</button>
<button type="button" class="btn btn-secondary" (click)="no()">No</button>
</div>`
})
export class UIConfirmComponent {
options: ConfirmOptions;
constructor(private state: ConfirmState) {
this.options = state.options;
}
yes() {
this.state.modal.close(true);
}
no() {
this.state.modal.close(false);
}
}
// MODULE
const UI_CONFIRM_COMPONENTS = [UIConfirmComponent];
const UI_CONFIRM_PROVIDERS = [ConfirmState, ConfirmService, IsPristineGuard];
@NgModule({
imports: [
CommonModule
],
declarations: UI_CONFIRM_COMPONENTS,
providers: UI_CONFIRM_PROVIDERS,
exports: UI_CONFIRM_COMPONENTS,
entryComponents: [
UIConfirmComponent
]
})
export class UiConfirmModule { }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment