что такое pipe angular
Pipes
Работа с pipes
Pipes представляют специальные инструменты, которые позволяют форматировать отображаемые значения. Например, нам надо вывести определенную дату:
Здесь создается дата, которая дважды выводится в шаблоне. Во втором случае к дате применяется форматирование с помощью класса DatePipe.
Встроенные pipes
В Angular есть ряд встроенных pipes. Основные из них:
CurrencyPipe : форматирует валюту
PercentPipe : форматирует проценты
UpperCasePipe : переводит строку в верхний регистр
LowerCasePipe : переводит строку в нижний регистр
DatePipe : форматирует дату
DecimalPipe : задает формат числа
SlicePipe : обрезает строку
Параметры в pipes
Pipes могут получать параметры. Например, пайп SlicePipe, который обрезает строку, может получать в качестве параметра, начальный и конечный индексы подстроки, которую надо вырезать:
Все параметры в пайп передаются через двоеточие. В данном случае slice:6:11 вырезает подстроку, начиная с 6 до 11 индекса. При этом, если начала выреза строки обязательно передавать, то конечный индекс необязателен. В этом случае в качестве конечного индекса выступает конец строки.
Форматирование дат
DatePipe в качестве параметра может принимать шаблон даты:
Форматирование чисел
DecimalPipe в качестве параметра принимает формат числа в виде шаблона:
value : само выводимое значение
digitsInfo : строка в формате «minIntegerDigits.minFractionDigits-maxFractionDigits», где
locale : код применяемой культуры
Форматирование валюты
CurrencyPipe может принимать ряд параметров:
value : выводимая сумма
currencyCode : код валюты согласно спецификации ISO 4217. Если не указан, то по умолчанию применяется USD
display : указывает, как отображать символ валюты. Может принимать следующие значения:
code : отображает код валюты (например, USD)
string : отображает произвольную строку
digitsInfo : формат числа, который применяется в DecimalPipe
locale : код используемой локали
Цепочки pipes
Вполне возможно, что мы захотим применить сразу несколько pipes к одному значению, тогда мы можем составлять цепочки выражений, разделенные вертикальной чертой:
Работа с pipes¶
Pipes представляют специальные инструменты, которые позволяют форматировать отображаемые значения. Например, нам надо вывести определенную дату:
Встроенные pipes¶
При применении классов суффикс Pipe отбрасывается (за исключением DecimalPipe — для его применения используется название number ):
Параметры в pipes¶
Все параметры в пайп передаются через двоеточие. В данном случае slice:6:11 вырезает подстроку, начиная с 6 до 11 индекса. При этом, если начала выреза строки обязательно передавать, то конечный индекс необязателен. В этом случае в качестве конечного индекса выступает конец строки.
Форматирование дат¶
DatePipe в качестве параметра может принимать шаблон даты:
Форматирование чисел¶
DecimalPipe в качестве параметра принимает формат числа в виде шаблона:
Форматирование валюты¶
CurrencyPipe может принимать ряд параметров:
Цепочки pipes¶
Вполне возможно, что мы захотим применить сразу несколько pipes к одному значению, тогда мы можем составлять цепочки выражений, разделенные вертикальной чертой:
Основы реактивного программирования с использованием RxJS. Часть 2. Операторы и пайпы
В предыдущей статье мы рассмотрели, что такое потоки и с чем их едят. В новой части мы познакомимся с тем, какие методы RxJS предоставляет для создания потоков, что такое операторы, пайпы(pipes) и как с ними работать.
Серия статей «Основы реактивного программирования с использованием RxJS»:
RxJS обладает богатейшим API. В документации описано более ста методов. Чтобы немного познакомиться с ними, мы напишем простое приложение и на практике посмотрим, как выглядит реактивный код. Вы увидите, что одни и те же задачи, которые раньше казались рутинными и требовали написания большого количества кода, имеют элегантное решение, если смотреть на них сквозь призму реактивности. Но прежде чем мы перейдем к практике, рассмотрим, как потоки можно представить графически, и познакомимся с удобными методами для их создания и обработки.
Графическое представление потоков
Чтобы наглядно продемонстрировать, как ведет себя тот или иной поток, я буду использовать принятую в реактивном подходе нотацию. Вспомним наш пример из предыдущей статьи:
Вот как будет выглядеть его графическое представление:
Поток обычно изображается в виде прямой линии. Если поток испускает какое-либо значение, то оно отображается на линии в виде кружка. Прямая черта в отображении — это сигнал завершения потока. Для отображения ошибки используется символ — “×”.
Потоки в одну строчку
В моей практике я редко сталкивался с необходимостью создавать свои экземпляры Observable напрямую. Большинство методов для создания потоков уже есть в RxJS. Чтобы создать поток, испускающий значения 1 и 2, достаточно лишь использовать метод of:
Метод of принимает на вход любое количество аргументов и возвращает готовый экземпляр Observable. После подписки он испустит полученные значения и завершится:
Если вы хотите представить массив в виде потока, то можно воспользоваться методом from. Метод from в качестве аргумента ожидает любой итерируемый объект(массив, строка и т.д.) или promise, и проецирует этот объект на поток. Вот как будет выглядеть поток, полученный из строки:
А вот так можно обернуть promise в поток:
Примечание: часто потоки сравнивают с promise. На самом деле, они имеют всего одну общую черту — push стратегию распространения изменений. В остальном это абсолютно разные сущности. Promise не может выдать несколько значений. Он может только выполнить resolve или reject, т.е. иметь только два состояния. Поток же может передавать несколько значений, и может быть повторно использован.
А помните пример с интервалом из первой статьи? Данный поток представляет собой таймер, который отсчитывает время в секундах с момента подписки.
Вот как в одну строчку можно реализовать то же самое:
И напоследок метод, который позволяет создать поток событий DOM элементов:
В качестве значений этот поток будет получать и испускать объекты события “keyup”.
Пайпы & операторы
Pipe — это метод класса Observable, добавленный в RxJS в версии 5.5. Благодаря ему мы можем строить цепочки операторов для последовательной обработки значений, полученных в потоке. Pipe представляет собой однонаправленный канал, который связывает между собой операторы. Сами операторы являются обычными функциями, описанными в RxJS, которые обрабатывают значения из потока.
Например, они могут преобразовать значение и передать его дальше в поток, или могут выполнять роль фильтров и не пропускать какие-либо значения, если они не соответствуют заданному условию.
Посмотрим на операторы в деле. Умножим каждое значение из потока на 2 с помощью оператора map:
Вот как выглядит поток до применения оператора map:
После оператора map:
Давайте воспользуемся оператором filter. Этот оператор работает точно так же, как функция filter в классе Array. Первым аргументом метод принимает функцию, в которой описано какое-либо условие. Если значение из потока удовлетворяет условию, то оно пропускается дальше:
И вот как будет выглядеть вся схема нашего потока:
Пишем приложение
Теперь, когда мы выяснили, что такое пайпы и операторы, можно приступать к практике. Наше приложение будет выполнять одну простую задачу: выводить список открытых репозиториев github по введенному никнейму владельца.
Требований будет немного:
Начнем с html разметки. Опишем input и ul элементы:
Затем в js или ts файле получим ссылки на текущие элементы используя browser API:
Ещё нам понадобится метод, который будет выполнять запрос к github API. Ниже приведен код функции getUsersRepsFromAPI, которая принимает на вход никнейм пользователя и выполняет ajax запрос, используя fetch. Затем возвращает promise, попутно преобразуя успешный ответ в json:
Следом напишем метод, который будет выводить список названий репозиториев:
Приготовления завершены. Настало время посмотреть на RxJS в действии. Нам необходимо слушать событие keyup нашего input’а. Первым делом мы должны понять, что в реактивном подходе мы работаем с потоками. К счастью, в RxJS уже предусмотрен подобный вариант. Вспомните метод fromEvent, который я упоминал выше. Используем его:
Теперь наше событие представлено как поток. Если мы посмотрим, что выводится в консоль, то увидим объект типа KeyboardEvent. Но нам нужно введенное пользователем значение. Вот тут-то нам и пригодится метод pipe и оператор map:
Перейдем к реализации требований. Начнем с того, что будем выполнять запрос, когда введенное значение содержит более двух символов. Для этого воспользуемся оператором filter:
С первым требованием разобрались. Приступим ко второму. Нам необходимо реализовать debounce. В RxJS есть оператор debounceTime. Данный оператор в качестве первого аргумента принимает число миллисекунд, в течение которых значение будет удерживаться, прежде чем пройдет дальше. При этом каждое новое значение будет сбрасывать таймер. Таким образом, на выходе мы получим последнее значение, после ввода которого прошло 700 миллисекунд.
Вот как может выглядеть наш поток без debounceTime:
А вот так будет выглядеть тот же поток, пропущенный через этот оператор:
С debounceTime мы будем реже обращаться к API, за счет чего получим экономию трафика и разгрузим сервер.
В целях дополнительной оптимизации предлагаю использовать еще один оператор — distinctUntilChanged. Данный метод избавит нас от дубликатов. Лучше всего показать его работу на примере:
Добавим данный оператор сразу после оператора debounceTime. Таким образом, мы не будем обращаться к API, если новое значение по какой-то причине совпадает с предыдущим. Подобная ситуация может возникнуть, когда пользователь ввел новые символы, а затем снова стер их. Так как у нас реализована задержка, в поток попадет только последнее значение, ответ на которое у нас уже есть.
Идем на сервер
Уже сейчас мы можем описать логику запроса и обработки ответа. Пока мы умеем только работать с promise. Поэтому опишем еще один оператор map, который будет вызывать метод getUsersRepsFromAPI. В наблюдателе опишем логику обработки нашего promise:
На текущий момент мы реализовали все, что хотели. Но у нашего примера есть один большой недостаток: нет обработки ошибок. Наш наблюдатель получает только promise и понятия не имеет, что что-то могло пойти не так.
Конечно, мы можем навесить catch на promise в методе next, но из-за этого наш код начнет все больше напоминать “callback hell”. Если вдруг нам понадобится выполнить еще один запрос, то сложность кода возрастет.
Примечание: использование promise в коде с RxJS считается антипаттерном. Promise имеет множество недостатков по сравнению с observable. Его нельзя отменить, и нельзя использовать повторно. Если перед вами стоит выбор, то выбирайте observable. То же самое касается метода toPromise класса Observable. Данный метод был реализован в целях совместимости с библиотеками, которые не могут работать с потоками.
Мы можем использовать метод from, чтобы спроецировать promise на поток, но этот способ чреват дополнительными вызовами метода subscribe, и также приведет к разрастанию и усложнению кода.
Решить эту проблему можно с помощью оператора mergeMap:
Теперь нам не нужно писать логику обработки promise. Метод from сделал из promise поток, а оператор mergeMap обработал его. Если promise выполнится успешно, то вызовется метод next, и наш наблюдатель получит готовый объект. Если же произойдет ошибка, то будет вызван метод error, и наш наблюдатель выведет ошибку в console.
Оператор mergeMap немного отличается от тех операторов, с которыми мы работали ранее, он принадлежит к так называемым Higher Order Observables, о которых я расскажу в следующей статье. Но, забегая вперед, скажу, что метод mergeMap сам подписывается на поток.
Обработка ошибок
Если наш поток получит ошибку, то он завершится. И если попытаться после ошибки взаимодействовать с приложением, то никакой реакции мы не получим, так как наш поток завершился.
Тут нам поможет оператор catchError. catchError вызывается только тогда, когда в потоке появляется ошибка. Он позволяет перехватить ее, обработать и вернуть в поток обычное значение, которое не приведет к его завершению.
Мы перехватываем ошибку в catchError и вместо нее возвращаем поток с пустым массивом. Теперь при возникновении ошибки мы очистим список репозиториев. Но затем поток снова завершится.
Все дело в том, что catchError подменяет наш оригинальный поток на новый. И дальше наш наблюдатель слушает только его. Когда поток of испустит пустой массив, будет вызван метод complete.
Чтобы не подменять наш оригинальный поток, вызовем оператор catchError на потоке from внутри оператора mergeMap.
Таким образом, наш оригинальный поток ничего не заметит. Вместо ошибки он получит пустой массив.
Заключение
Мы наконец-то перешли к практике и увидели, для чего нужны пайпы и операторы. Рассмотрели, как можно сократить код, пользуясь богатым API, которое предоставляет нам RxJS. Конечно, наше приложение не закончено, в следующей части мы разберем, как можно в одном потоке обрабатывать другой и как отменять наш http запрос, чтобы еще больше экономить трафик и ресурсы нашего приложения. А чтобы вы могли увидеть разницу, я выложил пример без использования RxJS, посмотреть его можно здесь. По этой ссылке вы найдете полный код текущего приложения. Для генерации схем я пользовался RxJS визуализатором.
Надеюсь, что данная статья помогла вам лучше понять, как устроен RxJS. Желаю вам успехов в изучении!
Что такое pipe angular
Angular pipe, или просто фильтр, нужен для преобразования данных прямо в HTML-шаблоне. Например, отображение даты и времени в желаемом формате или задание формата вывода числового значения.
В Angular имеется ряд встроенных фильтров, но также предусмотрена возможность создания собственных.
Рассмотрим пример использования встроенного date pipe.
Ниже приведен список некоторых наиболее часто используемых встроенных Angular pipe:
Отсчет выводимых элементов, как и индекс, начинается с нуля.
Полный список встроенных Angular pipe также можно найти в документации.
К одному значению допустимо одновременное применение нескольких фильтров.
Встроенные фильтры подходят в основном для решения «базовых» задач. Поэтому часто требуется создавать собственные (Angular custom pipe).
Как и компоненты, фильтры должны объявляться в свойстве declarations того модуля, в котором они будут использоваться.
Pure & Impure Angular pipes¶
Отличаются они по принципу работы механизма отслеживания изменений.
Для первого типа обновление выражения происходит только при его прямом изменении или смены ссылки, если речь идет о массивах и объектах.
Выражение с примененным к нему фильтром второго типа ( impure ) будет обновляться при любом изменении данных, а также в ответ на любое фиксирующееся в приложении событие, например, клик мыши.
Использование фильтров второго типа требуется в том случае, если фильтру передается массив или объект, изменение структуры или данных которых должно инициировать повторную обработку.
Для создания impure pipe в объекте, передаваемому декоратору, необходимо указать значение свойства pure false.
Создавать impure Angular pipe следует в исключительных случаях, поскольку такое частое обновление значения выражения требует больших ресурсов.
A Quick Guide To Angular Pipes
Impressive web development is the result of a successful synergy of robust back-end and an appealing front-end. Usually, the back-end is thought to be the ‘brains’ of a webpage and the front-end is merely the shiny exterior. However, with the right front-end development framework, powerful computations can happen directly on the front-end as well. Angular happens to be one of such impressive front-end development frameworks. Through its templates, Angular offers the opportunity for data to be processed and formatted in a certain way right there in the HTML code. This is made possible through functions with easy-to-understand syntax and usage, and they are called pipes.
This article will serve as a quick guide to tell you all the meaty stuff to know about pipes and how to effectively use them. Pipes come in various types and can significantly simplify data collection and processing in use cases where the front-end is the main gateway of obtaining the data. The article will also discuss how pipes are tested during the unit testing of Angular applications (which is not as difficult as it may seem for some).
The Ins And Outs Of Angular Pipes
Before moving on to discussing Angular pipes, it is imperative to understand what Angular components and templates are. Pipes are present in the template part of the component, making it necessary to understand the former to grasp the utility of the latter.
Angular applications are fundamentally made up of units called components. Each component is centered around a certain functionality or visual aspect of the application. These components are self-contained and consist of both its working logic along with instructions about its visual rendering. The latter is stored in what are called templates. Templates are simply HTML code that can be in the form of a separate file or inline code within the @Component decorator (which is written in TypeScript). An example of an Angular component can be seen below.
Here, the template URL is storing the relative path to a separate HTML file stored in the respective directory.
Usually, the functionality of the template is to mainly describe the visual layout of the component and show any data that is required. However, in cases like template-driven forms, the data that the back-end has to work with is mainly received through the front-end. Examples of these include a form taking in the personal details of a customer or information about a shipping order. The data received in such cases is mainly in the form of strings and instead of passing them as is to the back-end, pipes help us format them beforehand.
Pipes result in significant simplification of back-end logic and a smoother application, as in the above scenario. Oftentimes, data needs to be formatted in a particular way before being displayed. Once again, pipes come to the rescue here and avoid unnecessarily long code. One thing to note here is that pipes do not change the value of the variable, rather just formats it and inputs it as directed.
Using All The Different Kinds Of Angular Pipes
Pipes are used in the HTML code through the pipe operator ( | ). On one end of the operator, the variable whose value is to be formatted is placed and the particular formatting function(s) on the other hand. There can be multiple such functions, as we shall see in a bit. Given below is a short example of a simple pipe in action.
Here the date function is being used to simply format the value of todayDate into a regular date format. A specific format can be further specified, as in the example below. Through the fullDate, we also get the day today along with the full date.
One of the most interesting aspects of pipes is that they can be chained so that the data can undergo multiple formattings. In the following example, we obtain the date all in uppercase. Something similar is possible for formatting it into lowercase or even titlecase.
Various kinds of pipes exist, such as date, currency, decimal, JSON, and percentage, to name a few. However, the need to construct custom formatting can always arise in the rapidly expanding world of web development. That can be catered to through coding a particular pipe as required. Creating one’s own pipes is highly encouraged as it promotes easier-to-understand code and reusability of functionality throughout the code. Given below is an example of coding a custom pipe that raises a value to the exponent of some power given as well.
This pipe can now be used for a value in the following manner.
Pipes are mainly of two types:
Pipes that first check if the data is bound to a certain variable has changed with any kind of event and then run to update the value. These are called pure pipes.
Pipes run every time there is an event. These are called impure pipes.
As anyone can tell, it is better to strive towards creating pure pipes as the other kind can have a significant effect on the performance of the application. Impure pipes can prove expensive especially when used in chaining.
Testing Angular Pipes
Once an Angular application is complete, its unit testing is essential to further polish it and improve in any way necessary. If the said Angular application implements pipes for its purposes, then they are to be tested too. In particular, the pipes are tested to see if the formatting is working as intended and is handling corner cases as well. As pipes are straightforward functions that take in an input and throw out an output, testing pipes is really easy. Simply, they are provided with all kinds of boundary values to test if the transform() function is handling all kinds of parameters well and is giving intended values.
Conclusion
We saw how pipes can be used in our Angular applications to further improve its performance and do something as mundane as data formatting right there in the front-end. The article showed you all the different ways you could use pipes, alone and in chains, and the different kinds of pipes there are. To find out the full list of pipes provided by Angular itself, one can check out their pipes API documentation. We saw that testing the pipes is fairly easy and mainly focuses on the transform() function that the pipe implementation uses at the back-end. We discussed pure and impure pipes and also learned why the former is encouraged while the latter is discouraged.