Когда пользователь совершает какие-то критические и/или необратимые действия, перед тем, как отправить запрос на сервер, нужно запросить у пользователя подтверждение.
Как правило, выводится модал «Вы уверены, что хотите сделать то то и то то» и внизу две кнопки: Да и Нет. Если пользователь нажал «да», то отправляем запрос на сервер и закрываем модал. Если «нет», просто закрываем модал.
Это стандартный функционал, который обычно используется в нескольких местах в проекте. Также при наращивании функционала проекта, скорее всего добавиться еще несколько мест, где нужны модалы с подтверждением. Поэтому, во избежание дублирования кода, однозначно такой модал нужно выносить в отдельный компонент. Во избежание соблазна забивать костыли, этот компонент должен быть максимально универсальным и простым в использовании.
Перейдем от лирики к делу. Для отображения модала будем использовать Bootstrap.
Собственно мой вариант такого компонента:
yes-no-modal.component.html
yes-no-modal.component.ts
В параметры вынес заголовок предупреждения, текст предупреждения, цветовую схему/уровень важности (danger, info, warning), также можно переопределить надпись на кнопках.
Для показа модала вызываем showAsync, в который можем передавать произвольные данные. Эти же данные получаем в resolve/reject.
Далее подключаем модал в другом компоненте:
account.component.html
account.component.ts
На мой взгляд, использование такого решения выглядит максимально просто и читаемо.
Для сравнения, при использовании EventEmitter, придется определять два метода в каждом компоненте — showDeleteModal(), который вызывается кликом по кнопке удалить, и метод delete(), который вызывается по событию модала. Если у вас в одном компоненте будет несколько таких модалов на разные действия пользователя, то читаемость кода будет уже страдать.
В комментариях как всегда жду конструктивную и обоснованную критику.
Как правило, выводится модал «Вы уверены, что хотите сделать то то и то то» и внизу две кнопки: Да и Нет. Если пользователь нажал «да», то отправляем запрос на сервер и закрываем модал. Если «нет», просто закрываем модал.
Это стандартный функционал, который обычно используется в нескольких местах в проекте. Также при наращивании функционала проекта, скорее всего добавиться еще несколько мест, где нужны модалы с подтверждением. Поэтому, во избежание дублирования кода, однозначно такой модал нужно выносить в отдельный компонент. Во избежание соблазна забивать костыли, этот компонент должен быть максимально универсальным и простым в использовании.
Перейдем от лирики к делу. Для отображения модала будем использовать Bootstrap.
Собственно мой вариант такого компонента:
yes-no-modal.component.html
<div bsModal #yesNoModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog modal-{{type}}" role="document"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">{{title}}</h4> <button type="button" class="close" (click)="onNoClick()" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <p>{{body}}</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" (click)="onNoClick()">{{noBtnText}}</button> <button type="button" class="btn btn-{{type}}" (click)="onYesClick()">{{yesBtnText}}</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal -->
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<any> { return new Promise<any>((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
<app-yes-no-modal #deleteModal body="Вы действительно хотите удалить свой аккаунт?" title="Предупреждение" type="danger" ></app-yes-no-modal> <button (click)="delete()">Удалить</button>
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(), который вызывается по событию модала. Если у вас в одном компоненте будет несколько таких модалов на разные действия пользователя, то читаемость кода будет уже страдать.
В комментариях как всегда жду конструктивную и обоснованную критику.
