ngx-smart-modal-2
Version:
Smart modal handler to manage modals and data everywhere in Angular apps.
237 lines (220 loc) • 7.1 kB
text/typescript
import { Injectable } from '@angular/core';
import { NgxSmartModalComponent } from '../../';
import { ModalInstance } from './modal-instance';
export class NgxSmartModalService {
public modalStack: ModalInstance[] = [];
private debouncer: any;
/**
* Add a new modal instance. This step is essential and allows to retrieve any modal at any time.
* It stores an object that contains the given modal identifier and the modal itself directly in the `modalStack`.
*
* @param modalInstance The object that contains the given modal identifier and the modal itself.
* @param force Optional parameter that forces the overriding of modal instance if it already exists.
* @returns nothing special.
*/
public addModal(modalInstance: ModalInstance, force?: boolean): void {
if (force) {
const i: number = this.modalStack.findIndex((o: ModalInstance) => {
return o.id === modalInstance.id;
});
if (i > -1) {
this.modalStack[i].modal = modalInstance.modal;
} else {
this.modalStack.push(modalInstance);
}
return;
}
this.modalStack.push(modalInstance);
}
/**
* Retrieve a modal instance by its identifier.
*
* @param id The modal identifier used at creation time.
*/
public getModal(id: string): NgxSmartModalComponent {
return this.modalStack.filter((o: any) => {
return o.id === id;
})[0].modal;
}
/**
* Alias of `getModal` to retrieve a modal instance by its identifier.
*
* @param id The modal identifier used at creation time.
*/
public get(id: string): NgxSmartModalComponent {
return this.getModal(id);
}
/**
* Open a given modal
*
* @param id The modal identifier used at creation time.
* @param force Tell the modal to open top of all other opened modals
*/
public open(id: string, force = false): void {
const instance = this.modalStack.find((o: ModalInstance) => {
return o.id === id;
});
if (!!instance) {
instance.modal.open(force);
} else {
throw new Error('Modal not found');
}
}
/**
* Close a given modal
*
* @param id The modal identifier used at creation time.
*/
public close(id: string): void {
const instance = this.modalStack.find((o: ModalInstance) => {
return o.id === id;
});
if (!!instance) {
instance.modal.close();
} else {
throw new Error('Modal not found');
}
}
/**
* Toggles a given modal
* If the retrieved modal is opened it closes it, else it opens it.
*
* @param id The modal identifier used at creation time.
* @param force Tell the modal to open top of all other opened modals
*/
public toggle(id: string, force = false) {
const instance = this.modalStack.find((o: ModalInstance) => {
return o.id === id;
});
if (!!instance) {
instance.modal.toggle(force);
} else {
throw new Error('Modal not found');
}
}
/**
* Retrieve all the created modals.
*
* @returns an array that contains all modal instances.
*/
public getModalStack(): ModalInstance[] {
return this.modalStack;
}
/**
* Retrieve all the opened modals. It looks for all modal instances with their `visible` property set to `true`.
*
* @returns an array that contains all the opened modals.
*/
public getOpenedModals(): ModalInstance[] {
const modals: ModalInstance[] = [];
this.modalStack.forEach((o: ModalInstance) => {
if (o.modal.visible) {
modals.push(o);
}
});
return modals;
}
/**
* Get the higher `z-index` value between all the modal instances. It iterates over the `ModalStack` array and
* calculates a higher value (it takes the highest index value between all the modal instances and adds 1).
* Use it to make a modal appear foreground.
*
* @returns a higher index from all the existing modal instances.
*/
public getHigherIndex(): number {
const index: number[] = [1041];
const modals: ModalInstance[] = this.getModalStack();
modals.forEach((o: ModalInstance) => {
index.push(o.modal.layerPosition);
});
return Math.max(...index) + 1;
}
/**
* It gives the number of modal instances. It's helpful to know if the modal stack is empty or not.
*
* @returns the number of modal instances.
*/
public getModalStackCount(): number {
return this.modalStack.length;
}
/**
* Remove a modal instance from the modal stack.
*
* @param id The modal identifier.
* @returns the removed modal instance.
*/
public removeModal(id: string): void {
const i: number = this.modalStack.findIndex((o: any) => {
return o.id === id;
});
if (i > -1) {
this.modalStack.splice(i, 1);
}
}
/**
* Associate data to an identified modal. If the modal isn't already associated to some data, it creates a new
* entry in the `modalData` array with its `id` and the given `data`. If the modal already has data, it rewrites
* them with the new ones. Finally if no modal found it returns an error message in the console and false value
* as method output.
*
* @param data The data you want to associate to the modal.
* @param id The modal identifier.
* @param force If true, overrides the previous stored data if there was.
* @returns true if the given modal exists and the process has been tried, either false.
*/
public setModalData(data: any, id: string, force?: boolean): boolean {
if (!!this.modalStack.find((o: ModalInstance) => {
return o.id === id;
})) {
this.getModal(id).setData(data, force);
return true;
} else {
return false;
}
}
/**
* Retrieve modal data by its identifier.
*
* @param id The modal identifier used at creation time.
* @returns the associated modal data.
*/
public getModalData(id: string): any {
return this.getModal(id).getData();
}
/**
* Reset the data attached to a given modal.
*
* @param id The modal identifier used at creation time.
* @returns the removed data or false if modal doesn't exist.
*/
public resetModalData(id: string): any | boolean {
if (!!this.modalStack.find((o: ModalInstance) => {
return o.id === id;
})) {
const removed: any = this.getModal(id).getData();
this.getModal(id).removeData();
return removed;
} else {
return false;
}
}
/**
* Close the latest opened modal if it has been declared as escapable
* Using a debounce system because one or more modals could be listening
* escape key press event.
*/
public closeLatestModal(): void {
const me = this;
clearTimeout(this.debouncer);
this.debouncer = setTimeout(() => {
let tmp: ModalInstance | undefined;
me.getOpenedModals().forEach((m: ModalInstance) => {
if (m.modal.layerPosition > (!!tmp ? tmp.modal.layerPosition : 0 && m.modal.escapable)) {
tmp = m;
}
});
return !!tmp ? tmp.modal.close() : false;
}, 100);
}
}