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

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

Вот иллюстрация окончательного результата:

Давайте начнем.

Создание формы

Сначала создадим форму регистрации:

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

Создание компонента загрузки файлов

Продолжим компонент загрузки файла:

Мы зарегистрировали change прослушиватель событий, который генерирует файлы, загружаемые пользователем. В нашем случае нас интересует только один файл, поэтому мы будем использовать метод item(), передавая первый индекс для получения ссылки на него.

У нас также есть компонент прогресса, который отвечает за пользовательский интерфейс процесса загрузки (код опущен для краткости).

Создание настраиваемого элемента управления формы

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

Ошибка: нет средства доступа к значению для элемента управления формы с именем: ‘image’

Angular означает, что он не знает, как подключить наш компонент к API формы. Давайте проинформируем Angular, как это сделать, создав собственный метод доступа к значению:

Я не буду вдаваться в подробности того, что здесь происходит на самом деле, потому что у меня есть статья, посвященная этой теме:



Здесь важно отметить, что при изменении файла мы устанавливаем значение элемента управления как выбранный файл, и что всякий раз, когда мы вызываем control.patchValue(null) или control.reset(), мы очищаем ввод файла.

Посмотрим, что мы получим, прослушав событие valueChanges формы:

Отлично, наш image элемент управления содержит данные файла.

Создание настраиваемой проверки

Как мы видели ранее, мы хотим создать собственный валидатор, который позволяет загружать только файлы с расширением png:

Каждый раз, когда пользователь загружает файл, мы возвращаем true (недопустимое) значение, если его расширение не совпадает с тем, которое мы определили в валидаторе. В противном случае мы возвращаем null, что означает, что проверка прошла.

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



Отправить на сервер

Мы достигли момента, когда у нас есть необходимая информация, поэтому теперь пора отправить ее на наш сервер. Давайте реализуем метод submit:

Во-первых, нам нужно использовать FormData API, чтобы создать объект, содержащий поля выбранного значения, чтобы их можно было отправить на сервер через Ajax.

Мы создаем чистую и многократно используемую функцию, которая принимает объект, в нашем случае значение формы, и возвращает FormData экземпляр, содержащий его:

Затем мы хотим получать уведомления о ходе загрузки, поэтому нам нужно установить для параметра reportProgress значение true, а для параметра observe - значение events.

Затем мы подписываемся на наш наблюдаемый объект, чтобы инициировать запрос, и слушаем различные типы событий в течение жизненного цикла запроса. Теперь мы можем соответствующим образом реагировать в зависимости от типа события.

Стоит отметить, что в реальной жизни мы предпочли бы использовать службу, а не использовать службу HTTP непосредственно в компоненте.

Есть куда расти

Я хочу пойти дальше кода и сделать его многоразовым, а также написать его реактивным способом. Давайте создадим два пользовательских оператора, чтобы это стало возможным:

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

Теперь мы можем изменить существующий код следующим образом:

Намного лучше.

Конечная точка сервера

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

🔥 И последнее, но не менее важное: слышали ли вы об аките?

Акита - это модель управления государством, которую мы разработали здесь, в Datorama. Он успешно используется в среде производства больших данных, и мы постоянно добавляем в него функции.

Акита поощряет простоту. Он избавляет вас от хлопот по созданию шаблонного кода и предлагает мощные инструменты с умеренной кривой обучения, подходящие как для опытных, так и для неопытных разработчиков.

Я очень рекомендую это проверить.







Подпишитесь на меня в Medium или Twitter, чтобы узнать больше об Angular, Akita и JS!