Да, вы можете сделать так, чтобы раскрывающееся меню автозаполнения работало для двух входов

Это будет не очень короткое сообщение в блоге о том, как я настроил компонент автозаполнения Angular Material для получения результатов на основе двух полей ввода вместо одного.

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

Это выглядело как простая задача. Мы выбрали превосходный фреймворк Angular Material, и у меня возникла прекрасная идея использовать компонент автозаполнение из библиотеки материалов.

Я собирался предоставить текстовое поле. Пользователь собирался ввести имя врача, и вуаля, со списком врачей должно было отображаться раскрывающееся меню с автозаполнением, верно?

Неправильный.

Эта проблема

Я использовал реляционную базу данных, в которой имя врача хранилось в двух столбцах, называемых First_Name и Last_Name. Требование заключалось в том, чтобы я разрешил пользователю выполнять поиск по имени, фамилии или по обоим одновременно.

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

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

Решение

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

Когда я проверил компонент автозаполнения Angular Material, мне показалось, что он был разработан для одного поля ввода. Не было даже единой эталонной реализации для нескольких полей ввода, похоже, никто не пробовал это делать.

Тем не менее, я решил попробовать без особой надежды. И ниже мое решение, которое сработало!

Чтобы это сработало, нам нужно ответить на два вопроса:

  1. Как отобразить раскрывающееся поле автозаполнения, предназначенное для одного текстового поля для двух текстовых полей?
  2. Как вызвать событие автозаполнения, когда любое из этих текстовых полей имеет новое значение?

Отображение одного раскрывающегося списка автозаполнения для двух текстовых полей

Давайте посмотрим на HTML-код ниже построчно , чтобы понять, что происходит.

Строка 1

В строке 1 у нас есть начальная загрузка row div с атрибутом matAutocompleteOrigin. У нас также есть ссылочная переменная шаблона с именем #origin.

Атрибут matAutoCompleteOrigin делает div целевым кандидатом для отображения раскрывающегося списка автозаполнения. Мы будем использовать переменную #origin для привязки компонента автозаполнения к этому div в следующих строках.

Строка 5

В строке 5 мы определяем поле для ввода имени. С [matAutocomplete]=”auto” мы привязываем компонент автозаполнения к этому полю ввода. [matAutocompleteConnectedTo]=”origin” указывает браузеру отобразить раскрывающийся список автозаполнения относительно div, который мы определили в строке 1.

Строка 6

В строке 6 мы определяем наш компонент автозаполнения ссылкой на шаблон с именем #auto, на который мы ссылались в строке 5.

Мы также привязываем событие автозаполнения optionSelected к функции setFormData, чтобы иметь возможность настраивать поведение по умолчанию. Во втором разделе мы поговорим о функции setFormData.

Строки 7–11.

Строки 7–11 определяют наши параметры, которые будут отображаться в раскрывающемся списке автозаполнения. Мы зацикливаемся на physicians наблюдаемом с async каналом и отображаем имя и фамилию врача.

Строки 18–25.

Строки 18–25 делают то же самое для поля ввода фамилии, это не требует дополнительных пояснений.

Запуск одного и того же события автозаполнения для двух отдельных полей ввода

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

Давайте посмотрим на код построчно.

Строки 18–21.

В строках 18–21 при инициализации PhysicianInfoComponent мы выполняем два вызова функций setupPhysicianControls() и setupPhysiciansObservable().

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

Строки 23–41.

Поскольку настройка элементов управления формы тривиальна, мы сосредоточимся на методе setupPhysiciansObservable, который находится в строках с 23 по 41.

Объект Angular FormControl предоставляет свойство valueChanges, которое является наблюдаемым и испускает значение элемента управления формы каждый раз, когда его значение изменяется.

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

Оператор merge пригодится в таких сценариях, который объединяет две наблюдаемые в одну.

Строка 24

В строке 24 мы используем merge для объединения имени и фамилии valueChanges наблюдаемых.

Строка 26

Строка 26 задерживает передачу нового значения на 300 мс, чтобы дать пользователю время для выполнения своих критериев поиска перед запуском поиска.

Строки 27–32.

В строках 27–32 мы изменяем выдаваемый объект со значения одного поля ввода на значения полей ввода имени и фамилии. Это связано с тем, что наше требование состоит в том, чтобы позволить пользователю выполнять поиск одновременно по имени и фамилии.

Строка 33

Строка 33 ограничивает поисковый запрос более чем тремя символами. Таким образом, мы не запускаем поиск по запросу короче трех букв.

Строки 35–39.

Строки 35–39 выполняют внутренний запрос и сопоставляют объект response с response.body, который является массивом врача, что завершает настройку наблюдаемого врача.

setFormData Метод

Вторая важная функция, на которую мы должны обратить внимание, - это метод setFormData, о котором я упоминал в первом разделе.

В этом методе особенно важны строки 74–75, поскольку они переопределяют поведение компонента автозаполнения по умолчанию, когда элемент параметра выбирается из раскрывающегося списка.

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

Две строки довольно просты, но фокус в том, чтобы сделать вызовы setValue с параметром {emitEvent: false}.

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

Используя {emitEvent: false}, мы предотвращаем запуск события valueChanges, иначе это вызвало бы второй внутренний вызов через наш physicians наблюдаемый.

На этом пост завершается. Надеюсь, это поможет в ваших повседневных делах.

Удачного кодирования!