Создание в Angular шаблонов с функцией поиска

Создание в Angular шаблонов с функцией поиска

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

Как всегда, просто чтобы понять, как будет реализован в Angular поиск, давайте сначала посмотрим красивую визуализацию конечного результата:

И разметка для кода:

Создание Контейнера

Моей первой мыслью было использовать что-то вроде ViewChildren или ContentChildren, чтобы захватить searchable элементы, но у этого есть один большой недостаток.

В случае ViewChildren мы ограничены текущим представлением, а в случае ContentChildren — текущим разделом ng-content. Да, я знаю, что мы можем использовать опцию потомков ContentChildren, но нам нужна гибкость. Мы хотим дать пользователям возможность добавлять директивы searchable в любом месте иерархии шаблонов.

Для достижения этой цели мы использовали мощную функцию Angular - Element Injector. Как вы, возможно, знаете, мы, как и сервис, можем запросить Angular предоставить нам директиву через внедрение зависимостей. Например:

Затем Angular будет искать начальный элемент текущего хоста ParentComponent, пока не достигнет корневого компонента. Если Angular не сможет его найти, он выдаст ошибку, поэтому мы используем декоратор @Optional.

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

Мы определяем объект input, который принимает текущий поисковый термин, и вызываем вместе с ним метод search() (вскоре мы продемонстрируем реализацию этого метода). Мы также предоставляем методы register и директивы unregister для поиска. Давайте перейдем к SearchableDirective.

Создание директивы Searchable

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

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

Да, я знаю, что могу использовать метод insert() ViewContainerRef и оставить ссылку на представление, чтобы сохранить элементы, но это кажется излишним для моих потребностей.

Если по какой-то причине вам нужна эта возможность, вы всегда можете перейти к структурным директивам. Теперь вернемся к реализации метода search():

Когда мы получаем новый критерий поиска, нам нужно перебрать директивы searchable , проверить, есть ли совпадение, и запустить соответствующий метод.

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

Хотя это работает, это не мое любимое решение. Оно добавляет детали к шаблону, а затем мне нужно повторить себя и добавить значение поиска для каждого элемента. Короче это не DRY.

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

Создание директивы SearchableHighlight

Как я упоминал ранее, эта директива зависит от SearchableContainer и SearchableDirective, поэтому мы указываем Angular предоставить нам обе. Мы помечаем их как Optional() и выдаем ошибку, если не можем найти ни одной из них, потому что они необходимы.

Мы регистрируем экземпляр в контейнере, поэтому можем управлять им точно так же, как мы это делали с SearchableDirective. Метод highlight() принимает для поиска маркеры и текущее условие поиска и устанавливает принимающий элемент innerHTML после того, как я санировал его по соображениям безопасности.

Метод resolve() возвращает совпадающий термин обернутый в span, чтобы мы могли применить к нему стили CSS.
Давайте посмотрим на изменения SearchableContainer:

Мы добавили массив для хранения директив SearchableHighlight. Когда мы получаем новый поисковый термин, мы обрабатываем его через цикл и вызываем метод highlight(), передающий маркер и поисковый термин.

Обработка количества результатов

Давайте в конце добавим возможность просмотра количества результатов. Сначала мы добавим в наш компонент SearchableContainer счетчик:

Я не думаю, что есть необходимость объяснять приведенный выше код. Это простой счетчик, который отслеживает длину директив Searchables.

Теперь нам нужно ввести это в представление. Мы собираемся использовать функцию Angular, с которой не все знакомы — exportAs.

Я уже написал специальную статью по этой теме, но вкратце это свойство exportAs позволяет нам предоставлять директиву public API для шаблона. Теперь мы можем получить доступ в нашем шаблоне к экземпляру SearchableContainer:

Мы создаем локальную переменную с именем container, которая является ссылкой на экземпляр SearchableContainer.

Заключение

Фух … это было небыстро. Мы узнали, как можно использовать инжектор элементов Angular, чтобы очистить код и сделать его многократно используемым. Затем мы рассмотрели декоратор Optional() и функцию exportAs.

Конечно, это не конец. В нашем приложении код более оптимизирован, и мы поддерживаем «более поздние поступления». (подсказка: вы знаете, когда был добавлен новый поиск).

Цель состояла в том, чтобы вдохновить вас идеей создания компонентов с возможностью поиска в Angular. Вы можете взять код отсюда:

Автор: Netanel Basal

Источник: //netbasal.com/

Редакция: Команда webformyself.

Метки:

Похожие статьи:

Комментарии Вконтакте: