В этой статье я расскажу вам, как создать реактивную форму, которая включает загрузку файла вместе с обычными полями формы. Попутно мы создадим настраиваемый элемент управления формой для ввода нашего файла, добавим проверку и создадим настраиваемые операторы 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!