Заворачиваем в Promise модальное окно подтверждения действия
Когда пользователь совершает какие-то критические и/или необратимые действия, перед тем, как отправить запрос на сервер, нужно запросить у пользователя подтверждение.
Как правило, выводится модал «Вы уверены, что хотите сделать то то и то то» и внизу две кнопки: Да и Нет. Если пользователь нажал «да», то отправляем запрос на сервер и закрываем модал. Если «нет», просто закрываем модал.
Это стандартный функционал, который обычно используется в нескольких местах в проекте. Также при наращивании функционала проекта, скорее всего добавиться еще несколько мест, где нужны модалы с подтверждением. Поэтому, во избежание дублирования кода, однозначно такой модал нужно выносить в отдельный компонент. Во избежание соблазна забивать костыли, этот компонент должен быть максимально универсальным и простым в использовании.
Перейдем от лирики к делу. Для отображения модала будем использовать Bootstrap.
Собственно мой вариант такого компонента:
yes-no-modal.component.html
yes-no-modal.component.ts
import {Component, Input, OnInit, ViewChild} from '@angular/core';
import {ModalDirective} from 'ngx-bootstrap/modal';
@Component({
selector: 'app-yes-no-modal',
templateUrl: './yes-no-modal.component.html',
styleUrls: ['./yes-no-modal.component.css']
})
export class YesNoModalComponent implements OnInit {
@ViewChild('yesNoModal') public yesNoModal: ModalDirective;
@Input() private type = 'info';
@Input() private title = '';
@Input() private body = '';
@Input() private yesBtnText = 'Да';
@Input() private noBtnText = 'Нет';
constructor() { }
ngOnInit(): void {
}
public showAsync(data = null): Promise {
return new Promise((resolve, reject) => {
this.yesNoModal.show();
this.onYesClick = () => {
this.yesNoModal.hide();
resolve(data);
};
this.onNoClick = () => {
this.yesNoModal.hide();
reject(data);
};
});
}
private onYesClick(): any {}
private onNoClick(): any {}
}
В параметры вынес заголовок предупреждения, текст предупреждения, цветовую схему/уровень важности (danger, info, warning), также можно переопределить надпись на кнопках.
Для показа модала вызываем showAsync, в который можем передавать произвольные данные. Эти же данные получаем в resolve/reject.
Далее подключаем модал в другом компоненте:
account.component.html
account.component.ts
import {Component, OnInit, ViewChild} from '@angular/core';
import {YesNoModalComponent} from '../_common/yes-no-modal/yes-no-modal.component';
import {DeleteUserEndpoint} from '../../api/delete-user.endpoint';
import {ErrorService} from '../../services/error/error.service';
@Component({
selector: 'app-account',
templateUrl: './account.component.html',
styleUrls: ['./account.component.css'],
providers: [DeleteUserEndpoint]
})
export class AccountComponent implements OnInit {
@ViewChild('deleteModal') public deleteModal: YesNoModalComponent;
constructor (private deleteUserEndpoint: DeleteUserEndpoint) {
}
delete(data) {
this.deleteModal.showAsync(data).then(result => {
this.deleteUserEndpoint.execute(result);
});
}
ngOnInit(): void {
}
}
На мой взгляд, использование такого решения выглядит максимально просто и читаемо.
Для сравнения, при использовании EventEmitter, придется определять два метода в каждом компоненте — showDeleteModal (), который вызывается кликом по кнопке удалить, и метод delete (), который вызывается по событию модала. Если у вас в одном компоненте будет несколько таких модалов на разные действия пользователя, то читаемость кода будет уже страдать.
В комментариях как всегда жду конструктивную и обоснованную критику.