Сообщество Angular быстро развивается, и появляется множество новых библиотек и плагинов для популярного фреймворка, поддерживаемого Google. Сегодня я собираюсь подробнее остановиться на PrimeNG, библиотеке компонентов пользовательского интерфейса, разработанной PrimeTek Informatics.

Я использовал PrimeNG в качестве основного источника компонентов пользовательского интерфейса в недавнем рабочем проекте, а также тщательно изучил его исходный код, даже внес небольшой вклад (хотя мой запрос на вытягивание до сих пор не был принят или отклонен на их GitHub »), Поэтому мне есть чем поделиться, основываясь на моем (часто отрицательном) опыте.

Итак, приступим.

Плюсы

Я не хочу показаться слишком предвзятым, поэтому хочу начать с упоминания некоторых реальных преимуществ, которыми обладает эта библиотека. Во-первых, он хорошо составлен и в значительной степени понятен (хотя я расскажу о некоторых проблемах согласованности позже), его исходный код ясен и по большей части хорошо организован, и его можно легко использовать с Angular. Было очень приятно погрузиться в это (я был очень взволнован, когда сделал свой первый вклад), и это действительно расширяет наши знания о том, как действительно взаимодействуют компоненты Angular.

Минусы

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

Несогласованный API

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

Мы знаем, что компоненты могут быть вложенными, и что они создают отдельные «области» (как мы использовали бы это слово, говоря об angular.js, первой версии фреймворка Angular) и могут взаимодействовать с внешним миром с помощью входных данных. и выходы. PrimeNG ничем не отличается и использует тот же подход.

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

Но с выводами может быть немного сложнее. Компоненты обычно имеют селекторы и шаблоны, определенные как их метаданные, и всякий раз, когда мы используем селекторы компонента внутри другого шаблона компонентов, мы фактически заполняем этот настраиваемый HTML-тег шаблоном и логикой вложенного компонента. Вот небольшой пример (для краткости опущены импорт и объявления модулей):

Обратите внимание, как шаблон ParentComponent использует селектор «nested-component» для создания и ввода внутри него. Обратите внимание на одну особенность Parent: для него определен метод onBlur, который мы будем вызывать, когда пользователь оставляет ввод во вложенном компоненте… но как? У нас нет доступа к внутренним компонентам вложенного компонента, и мы не можем напрямую привязать метод из ParentComponent к событию ввода (размытие) внутри вложенного. Обходной путь к этой проблеме - вывод:

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

Проблема с PrimeNG здесь в том, что он состоит из компонентов, но не может предоставить все (или, по крайней мере, базовые) события для привязки из вашего кода. Возьмем, к примеру, компонент Автозаполнение. Эта конкретная проблема связана с предыдущей версией и к настоящему времени исправлена, но есть много других подобных недостающих точек API. Компонент p-AutoComplete предоставил вывод (onFocus), который испустил событие (focus) исходного элемента ввода внутри этого компонента, но не предоставил вывод (onBlur)! Клиенту нужно было показывать информационную метку всякий раз, когда пользователь фокусируется на вводе автозаполнения, что было легко сделать с выводом (onFocus), и, логически, сообщение было бы удалено, как только пользователь ушел от ввода, что было Напротив, невозможно, потому что не было события, к которому можно было бы привязать метод.

Еще один отличный пример - компонент GrowlMessage, который обеспечивает вывод (onClose), к которому я могу привязать метод, который будет вызываться всякий раз, когда пользователь закрывает конкретное сообщение, но он не может предоставить такое базовое событие, как щелчок! Я не могу вызвать метод, когда пользователь нажимает на одно из сообщений, потому что такое событие не испускается из компонента! (Это привело к тому, что мы сделали грязный взлом, перехватив событие щелчка с помощью jQuery, найдя соответствующее сообщение в массиве наших сообщений и только затем вызвав для него метод). Кстати, запрос на перенос, который я отправил PrimeNG, касался добавления события щелчка для этого компонента, надеюсь, он будет принят как можно скорее.

Не совсем настраиваемый

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

Я действительно, ДЕЙСТВИТЕЛЬНО должен передать массив объектов, которые выглядят так. Вот как это работает в идеальном мире PrimeNG. На самом деле такой массив у меня не всегда бывает. Обычно я визуализирую это раскрывающееся меню, используя список, полученный с сервера, который предоставляет мне полные пользовательские данные, в которых отсутствуют значения "значения" и "метки":

Итак, если я хочу, чтобы свойство пользователя id было моим раскрывающимся значением, а fullName - меткой, я должен сопоставить моих пользователей с новым массивом:

Знаете, что было бы хорошо? Атрибуты «dataKey» и «labelKey» в раскрывающемся компоненте, чтобы сообщить ему, какие атрибуты в массиве объектов искать при рендеринге раскрывающегося списка! Именно так:

Ирония заключается в том, что компонент Autocomplete (который также отображает раскрывающийся список) имеет атрибут «dataKey» для определения свойства, которое будет использоваться в качестве значения для раскрывающегося списка, и атрибут «field», который будет использоваться в качестве метки. Это заставляет задуматься: почему такая функция присутствует в одном компоненте, но полностью отсутствует в другом? Несогласованный API!

Несколько слов о шаблонах

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

Довольно мило, да? Проблема в том, что PrimeNG не предоставляет шаблоны для всех ожидаемых компонентов. Рассмотрим компонент Lightbox (он отображает галерею изображений, которые можно увеличивать и просматривать в виде слайд-шоу). Вот простое использование:

Его очень легко использовать, если вы не хотите чего-то более конкретного, например, кнопки на каждом эскизе изображения, чтобы удалить его из списка. Это не сработает так, как вы думаете: для Lightbox нет шаблонов. Есть атрибут «type =» content »’, но он оставляет весь процесс рендеринга разработчику и обычно предназначен для отображения одного элемента, такого как iframe.

Делаем вещи программно

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

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

И да, если быть более точным, несколько диалоговых окон в PrimeNG допустимы, но несколько ConfirmDialog-ов - нет - они вызывают странное поведение слоя, и диалоговое окно не становится видимым.

PrimeNG знает лучше

Ну, иногда PrimeNG просто предполагает, что знает, чего вы хотите. Рассмотрим компонент FileUpload:

Где атрибут «url», куда будут загружены файлы. Он отображает красивую рамку с такими миниатюрами изображений:

Ну хорошо, правда? Но что, если я не хочу выгружать изображения прямо из этого компонента, а скорее являются частью более крупной формы с множеством других данных, которые должны быть переданы на сервер одновременно? Похоже, сделать это непросто: FileUpload не поддерживает привязку к Angular Reactive Form или ngModel. Если вы хотите выполнить привязку, вы должны сделать это вручную (FileUpload запускает событие, когда пользователь добавляет новые файлы, можно выполнить привязку к нему и вручную добавить файлы из объекта события в форму / ngModel).

Другой

Иногда документация может вводить в заблуждение: события отсутствуют, иногда даже атрибуты, и да, у меня была серьезная проблема с пониманием того, когда «атрибут» (как он указан в документации) действительно просто атрибут или, скорее, связываемое свойство ('attr = ”someValue”' vs '[property] = ”someVariable”').

Так что же тогда?

Стоит ли вам по-прежнему рассматривать PrimeNG для ваших будущих проектов? Определенно да, но:

  • Будьте осторожны: если вы уже знаете, что вам понадобится больше настроек и привязок событий, как в приведенных выше примерах, возможно, для вас есть что-то получше.
  • Будьте готовы погружаться в исходный код чаще, чем ожидалось, так как иногда документация немного отстает от реальной ситуации.
  • Никогда, НИКОГДА не делайте предположений типа «Я просто сделаю то же самое с этим компонентом, что и с другим», как упоминалось выше, несогласованность в этом API не редкость.

PrimeNG молод, как и Angular. Надеюсь, что рано или поздно он станет более стабильным и последовательным.