# Pipes

## About

{% embed url="<https://angular.dev/guide/pipes>" %}
guide/pipes
{% endembed %}

**Are simple functions to use in templates to accept an input value and return a transformed value.**

*If you want to change the value to output in the Template but you don't want to change it in the variable itself.*

They can be used throughout your application, while only declaring each pipe once.

```html
<p>{{ username | uppercase }}</p>
```

## [Generate Pipe (CLI)](https://angular.dev/cli/generate/pipe)

```bash
ng g pipe [pipe-name] [options]
```

## Best Practices

* **Avoid adding filtering and sorting logic to pipes**. As Angular can call pipe methods many times per second, using these logics can degrade user expirience.
* With ternaries, wrap the ternaries in parenteses first.

#### Using Pipes with Ternary Operators `?:`

Beware that pipes will have highers precedence over ternary operator.

```typescript
condition ? a : b | pipe;

// Will be evaluated to
condition ? a : (b | pipe);

// The right way is to wrap the ternary in parentheses
(condition ? a : b) | pipe;
```

## Change Detection and Pipes

Executing a pipe to update the display with every change would slow down the application's performance. So Angular uses a faster change-detection algorithm for executing a pipe (Pure Change).

With pure pipes, Angular ignores changes (mutations) within `Objects` and `Arrays` because checking a primitive value or object reference is much faster than performing a deep check for differences within objects.

{% hint style="info" %}
So a pure pipe with arrays or objects may not work the way expected, if you are mutating the array or object.

*This means that Angular probably won't detect the change, and update the display.*
{% endhint %}

{% hint style="success" %}
**The right way is to treat arrays and objects as immutable**, so if you need to update them, provide a new array or object.
{% endhint %}

## **Purity**

### **Pure Change**

By default, pipes are defined as pure so that Angular executes the pipe only when it detects a pure change to the input value or parameters.

A pure pipe, is a pipe that uses a pure function, that processes inputs and returns values without side effects.

In other words, given the same input, a pure function should always return the same output.

The pure change is either:

* A change to a primitive input value such as (`String`, `Number`, `Boolean`, `Symbol`).
* Or a changed object reference such as (`Date`, `Array`, `Function`, `Object`).

### Unpure Pipes (AVOID)

To disable pure pipes, and allow Angular to detect changes when mutating `Objects` and `Arrays`.

{% hint style="warning" %}
**But be aware that ANY change on the page WILL TRIGGER the pipe to be re-ran.**
{% endhint %}

{% hint style="warning" %}
Long-running impure pipes could dramatically slow down the application.
{% endhint %}

```typescript
@Pipe({
    name: '...',
    pure: false
})
```

## Pipes Parameters

Pipes can take additional parameters with `:` that configure the transformation, like:

```html
{{ pipeFunc:param1:param2:... }}
```

```html
{{ userdate | date:'fullDate' }}
```

## Chaining pipes

You can connect multiple pipes so that the output of one pipe becomes the input to the next.

Always parsed from left to right. *(So their order matter, and might impact the result)*

```html
{{ userdate | date:'fullDate' | uppercase }}
```

## Custom pipes

Create a `something.pipe.ts` to hold the code.

Use `UpperCamelCase` for the pipe class name, and `camelCase` for the corresponding pipe name.

{% hint style="info" %}
*Implement* `PipeTransform` *interface when creating pipes.*
{% endhint %}

```typescript
@Pipe({
    name: "shortenTheWorld",
})
// It is good practice to implement the 'PipeTransform' interface in your custom class
export class ShortenTheWorldPipe implements PipeTransform {
    // Receiving only the value
    transform(value: any) {
        if (value.length > 10) return value.substr(0, 10) + "...";
        return value;
    }

    // Or

    // Receiving also a parameter
    transform(value: any, limit: number, ...) {
        if (value.length > limit) return value.substr(0, limit) + "...";
        return value;
    }
}
```

```html
{{ username | shortenTheWorld }} {{ username | shortenTheWorld:10 }}
```

## AsyncPipes

Are pipes to be ran on data that are async, like `Promise` or `Observable`.

```typescript
@Component({
    imports: [AsyncPipe],
    template: `
        <!-- With async pipe, it will subscribe to the promise and listen to change, outputing the correct value -->
        <p>{{ appPromise | async }}</p>
        <p>{{ appObservable$ | async }}</p>
    `
})
export class Component {
    protected appPromise = new Promise((resolve) => {
	setTimeout(() => {
	    resolve("Promise Resolved");
        }, 2000);
    });

    protected appObservable$: Observable<string> = ...;
}
```
