Еще одна и, возможно, последняя статья о том, как сделать это с нуля для Angular. На мой взгляд, это довольно просто, и опять же, каждая библиотека пользовательского интерфейса должна иметь лучшую реализацию диалогов. Это просто доказательство концепции.

Я не буду сильно беспокоиться об именах или CSS. Итак, без дальнейшего промедления…

Часть 1. Простые диалоги

Под простым я подразумеваю базовый диалог Ok/Cancel. Вы можете вызвать его из любого вложенного компонента через сервис, немного настроить и реагировать на ответ пользователя. Итак, нам нужно создать компонент и сервис, как обычно:

ng g c simple-dialog // create component
ng g s dialog // create service

Нам также нужен интерфейс для передачи данных:

Простые вещи, которые можно расширить при необходимости. Установите заголовок, сообщение и должна ли быть видна кнопка отмены. Может быть, вы просто хотите передать пользователю важную информацию, так что выбора нет.

okHandler — это действие, которое будет выполнено, если выбор задействован и пользователь нажимает «ОК».

Вы можете расширить этот интерфейс, например, с помощью okLabel, чтобы вы могли настроить текст кнопки при вызове. Хотя здесь я этого делать не буду, только barebones.

Переходим к сервису, все довольно просто:

Всего 3 вещи. Субъект, геттер, на который подписывается компонент диалогового окна, и открытая функция для вызова диалогового окна.

Переходим к самому диалогу, сначала файл скрипта:

Мы внедряем службу диалога и подписываемся на нее. Когда кто-то вызывает диалог, мы передаем IDialogConfig данные в open() функцию. Затем мы назначаем значения конфигурации по умолчанию, если они не были предоставлены, поэтому вам не нужно указывать каждую вещь каждый раз, когда вы хотите вызвать диалог. Наконец, мы переключаем dialogVisible на true. Также есть функция close(). Если пользователь нажал OK, выполните okHandler и переключите видимость диалогового окна.

Переходя к HTML, вы просто подключаете config данные к нужным местам:

Довольно простой, расширяйте его по своему желанию. Вот копируемый CSS:

.dialog-background {
    z-index: 1000;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: #00000044;
}
.dialog-content {
    padding: 1rem;
    background-color: #ffffff;
    width: 25%;
}
.dialog-footer {
    display: flex;
    justify-content: flex-end;
    align-items: center;
}

Теперь пришло время протестировать его. Обязательно поместите <app-simple-dialog> вверху app.component.html .

Примечание:

До сих пор я писал о нескольких распространенных компонентах пользовательского интерфейса. Уведомления, загрузчики страниц и теперь диалоги. В каждой статье я говорил, что все эти компоненты должны находиться в верхней части app.component.html. Уведомления должны быть вверху, затем загрузчик страниц, затем диалоги.

Вернемся к тестированию. Я вызову диалог из app.component, но имейте в виду, что это работает для любого вложенного компонента. Итак, HTML:

И призыв:

Мы внедряем службу и вызываем функцию open(). Обратите внимание, что я предоставил только сообщение и okHandler, и даже это необязательно. okHandler должен быть обернут таким образом, чтобы избежать проблем с областью действия класса.

Конечный результат:

Часть 2 — оболочка диалогового окна

Обычно у всех больших приложений есть хотя бы одна ситуация, когда им нужно, чтобы сложные компоненты отображались в диалогах. Если вы хотите сохранить согласованность пользовательского интерфейса, вам не нужно переписывать стиль заголовка и каждый раз показывать/скрывать функциональность. Сухой принцип и тот джаз.

Вместо того, чтобы записывать эти компоненты в виде диалогов, вы должны создать компонент-оболочку диалога с общей функциональностью и спроецировать в него целевой компонент.

Angular поддерживает проекцию контента (отображение HTML одного компонента в другом), и его очень легко использовать. Я не буду вдаваться в подробности, вы можете найти официальные документы, хотя, честно говоря, StackOverflow — ваш друг здесь, когда я последний раз проверял.

Начнем с создания компонента диалоговой оболочки. Для этого нам не нужна служба, так как она будет вызываться по-другому.

ng g c dialog-wrapper

Сначала файл сценария:

Мертвая простота. Я не считаю нужным писать об этом пошаговое руководство. Интересная часть находится в HTML:

Вы можете повторно использовать классы CSS, указанные выше. Я признаю, что синтаксис немного странный. Самое интересное с этими тегами <ng-content>. Вот тут-то и появляется проекция контента, и как она работает, лучше всего понять, когда увидишь.

Снова поместите оболочку диалога вверху app.component.

Давайте создадим компонент, который мы собираемся спроецировать в оболочку диалога. Опять же, представьте, что он должен представлять собой какой-то очень сложный компонент с кучей внедренных сервисов, подкомпонентов и многого другого. Чтобы избежать бесполезного беспорядка, мой будет использоваться для создания простого объекта Todo. Тем не менее, обращайтесь с ним так же, как с любым другим угловым компонентом.

ng g c create-todo

Сначала HTML:

Помните, я сказал поставить <app-dialog-wrapper> над app.component? Тем не менее, у нас снова есть этот тег. Тот, что находится в компоненте приложения, определяет, где контент будет отображаться в модели DOM. Тот, что здесь, определяет, какой контент будет отображаться (или, скорее, проецироваться в эти теги ng-content).

Видите селекторы на этих двух элементах div? Каждый будет отображаться в соответствующем теге <ng-content>. Даже если вы перевернете позиции div здесь, нижний колонтитул всегда будет ниже основного.

Мы также добавили селектор #wrapper, чтобы мы могли получить доступ к функциям диалоговой оболочки. Мы также устанавливаем входной параметр заголовка (заголовок/заголовок диалога).

Теперь давайте проверим файл TS:

У нас есть специальная функция open, которая создает пустой объект todo (чтобы избежать нулевых ошибок), а затем мы используем функциональность обертки для фактического отображения диалогового окна. cancel() просто закроет все.

Также обратите внимание, что createTodo() лишен логики создания. Что именно там происходит, зависит от реализации. Помните, что это должно представлять какой-то сложный компонент. Этому диалоговому окну не нужно возвращать что-либо вызывающему компоненту.

Вы можете отправить todo через Output . Вы можете передать его какому-нибудь TodoService . Вы можете вызвать бэкэнд оттуда. Это зависит…

Давайте проверим все это в app.component, но имейте в виду, что это можно использовать в любом вложенном компоненте:

И файл ТС:

Вот и все . Выглядит ужасно, но я отказываюсь использовать CSS :P

Напутствие

Я надеюсь, что это было познавательное чтение. Несмотря на то, что я не фокусировался на CSS, я хочу поделиться небольшой жемчужиной, касающейся стиля и поведения модальных окон:

https://developers.google.com/web/fundamentals/design-and-ux/animations/animating-modal-views

Спасибо за прочтение :)