Angular
Instalación
- Angular CLI
- Comandos de Angular para correr un proyecto
- Estructura de un proyecto en Angular
- Ejemplos básicos de TypeScript para usar en Angular
- Data binding con ngModel
- Estructuras de control
- Uso de *ngIf
- Uso de *ngFor
- *ngFor para arrays
- Uso de ngSwitch
- Extensión para navegadores para desarrollar en Angular
- Estilos en Angular
- NgClass & NgStyle
- Creando un formulario
Estructura de ficheros en Angular
Componentes
One way data binding
Two way data binding
¿String Interpolation o Property [Binding]?
Directivas
Directivas de atributos
Ciclo de vida de un componente
Event binding
¿Qué es un decorador?
Instalación
Angular CLI
npm i -g @angular/cli
Comandos de Angular para correr un proyecto
- Siguiente comando a ejecutar es :
ng version
- Comando para crear un proyecto:
ng new my-app
- Correr servidor en Angular:
ng serve
, con la opción-o
abre el navegador por defecto. - Cambiar de puerto:
ng serve -o --port=3500
- Con
ng version
dentro de un proyecto podemos ver las dependencias que trae el proyecto.
Estructura de un proyecto en Angular
- La carpeta src es donde se desarrolla.
- El archivo .browserslistrc figuran los navegadores a los cuales se les puede dar soporte.
- El archivo .editorconfig se establecen las normativas para trabajar en equipo (identación, etc), hay que tener instalado la extesión en vscode.
- Una extensión para vscode que ayuda en el desarrollo es Angular Language Service
- Una recomendación es agregar un archivo .nvmrc en el proyecto e indicar la versión que se está utilizando de node.
Ejemplos básicos de TypeScript para usar en Angular
- Asignar tipo de dato:
const username: string | number = "gamcode";
//Se está diciendo que username puede ser de tipo string o number
- Ejemplo de una función suma:
const suma = (a: number, b: number) => {
return a + b;
};
suma(2, "asdad"); //Marca error de sintaxis en vscode algo que no sucede con vanilla JS
Angular usa el concepto de POO
- Ejemplo:
class Person {
age: number;
lastName: string;
constructor(age: number, lastName: string) {
this.age = age;
this.lastName = lastName;
}
}
- Otra forma de hacer lo mismo:
class Person {
constructor(public age: number, public lastName: string) {}
}
- Se lo puede usar:
const gabriel = new Person(23, "Mamani");
gabriel.age;
Data binding con ngModel
<!--Archivo app.component.html-->
<h1>ngModel</h1>
<p>Nombre: {{thing.name}}</p>
<input type="text" required #nameInput="ngModel" [(ngModel)]="thing.name" />
<p>Valid: {{nameInput.valid}}</p>
<br />
<p>Number: {{thing.number}}</p>
<input
type="number"
max="100"
min="1"
required
#numberInput="ngModel"
[(ngModel)]="thing.number"
/>
<p>Valid: {{numberInput.valid}}</p>
Para que funcione ngModel hay que importarlo
// Archivo app.module.ts
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { FormsModule } from "@angular/forms"; // Esto se importa
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AppRoutingModule, FormsModule], // Aqui tambien se lo coloca
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
Estructuras de control
Uso de *ngIf
<h1>*ngIf</h1>
<input type="text" required [(ngModel)]="thing.name" />
<p *ngIf="thing.name === 'gabriel'">Soy Gabriel</p>
<p *ngIf="thing.name === 'alejandro'">Soy Alejandro</p>
<!--Si se cumple, se muestra -->
<!--Tambien se puede hacer condicionales &&-->
<p *ngIf="thing.name === 'alejandro' && thing.number === 22; else elseBlock">
Soy Alejandro
</p>
<!-- Bloque de tipo else -->
<ng-template #elseBlock>
<!-- El nombre que acompaña al #, es cualquiera -->
<p>Bloque de else</p>
</ng-template>
Uso de *ngFor
// Archivo app.component.ts
names : string[] | number[]= ["Gabriel", "Alejandro", "Simón"]
//any[] -> Indica que queremos cualquier valor, no es buena practica
<h1>*ngFor</h1>
<ul>
<!-- name es el nombre del item (variable temporal) a iterar, names es el array -->
<!-- Para obtener el indice se usa index y lo renombramos con i egg-->
<li *ngFor="let name of names; index as i">{{i}} - {{name}}</li>
</ul>
- Crear una lista dinamicamente y eliminar un item.
// Archivo app.component.ts
newName = "";
addName(){
this.names.push(this.newName);
this.newName = "";
}
deleteName(index: number){
this.names.splice(index,1);
}
<h1>*ngFor</h1>
<input type="text" required [(ngModel)]="newName" />
<button (click)="addName()">Add name</button>
<ul>
<!-- name es el nombre del item (variable temporal) a iterar, names es el array -->
<!-- Para obtener el indice se usa index y lo renombramos con i egg-->
<li *ngFor="let name of names; index as i">
{{i}} - {{name}}
<button (click)="deleteName(i)">Delete</button>
</li>
<li *ngIf="names.length === 0">No hay nombres</li>
</ul>
*ngFor para arrays
// Archivo app.component.ts
products = [
{
name : "coso",
price : 231,
image : "./assets/images/toy1.jpg"
}{
name : "coso 2",
price : 291,
image : "./assets/images/toy2.jpg"
}{
name : "coso 3",
price : 211,
image : "./assets/images/toy3.jpg"
}{
name : "coso 4",
price : 221,
image : "./assets/images/toy4.jpg"
}
]
- Hay que asignarle un tipado al array de productos, entonces se usa las interfaces.
//Archivo product.model.ts
//La interface es una forma que nos dice que tipo de atributos debería tener cada objeto
export interface Product {
name: string;
price: number;
image: string;
}
- Ahora se lo importa
// Archivo app.component.ts
import {Product} from "./product.model"
//Los : (dos puntos) significa asignar un tipado
products: Product[] = [
{
name : "coso 1",
price : 231,
image : "./assets/images/toy1.jpg"
category: "all",
}{
name : "coso 2",
price : 291,
image : "./assets/images/toy2.jpg"
}{
name : "coso 3",
price : 211,
image : "./assets/images/toy3.jpg"
}{
name : "coso 4",
price : 221,
image : "./assets/images/toy4.jpg"
}
]
- Como category no existe, vscode avisa que algo anda mal, para solucionarlo se puede hacer que sea opcional agregando a la interfaz dicho atributo con un signo de pregunta ?
export interface Product {
name: string;
price: numb er;
image: string;
category?:string;
}
- *ngFor solo funciona en objetos que puedan iterarse
Uso de ngSwitch
<h2>ngSwitch</h2>
<input type="text" required [(ngModel)]="thing.name" />
<div [ngSwitch]="thing.name">
<p *ngSwitchCase="'gabriel'">La persona es gabriel</p>
<p *ngSwitchCase="'alejandro'">La persona es alejandro</p>
<p *ngSwitchCase="'simon'">La persona es simon</p>
<p *ngSwitchDefault>No hace match</p>
</div>
<!--
Esto se haria si solo se usara *ngIf
<p *ngIf=" thing.name==='gabriel'">La persona es gabriel</p>
<p *ngIf=" thing.name==='alejandro'">La persona es alejandro</p>
<p *ngIf=" thing.name==='simon'">La persona es simon</p>
-->
Extensión para navegadores para desarrollar en Angular
Angular Dev Tools
Estilos en Angular
La primera forma es la normal
La otra es: Dynamic Class & Style
// Archivo app.component.ts
widthImg = 10;
<h1>Class & Style</h1>
<input type="text" required #nameInput2="ngModel" [(ngModel)]="thing.name" />
<!-- invalid es el nombre de la clase -->
<p class="message-error" [class.invalid]="nameInput2.invalid">
El campo es requerido
</p>
<br />
<label>Nombre</label>
<!-- Como estilo en linea-->
<input type="text" required #nameInput3="ngModel" [(ngModel)]="thing.name" />
<p [style.font-style]="nameInput3.invalid ? 'italic' : 'normal'">
Texto texto texto
</p>
<br />
<div class="styles">
<div>
<input type="text" [(ngModel)]="widthImg" />
</div>
<div>
<img [style.width.px]="widthImg" [src]="thing.avatar" />
</div>
</div>
<hr />
- CSS del código HTML anterior
.message-error {
background-color: red;
color: white;
opacity: 0;
transition: all linear 0.5s;
&.invalid {
opacity: 1;
}
}
.styles {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
NgClass & NgStyle
<h2>NgClass</h2>
<input type="text" required #nameInput4="ngModel" [(ngModel)]="thing.name" />
<!-- Si se sigue con esto puede llegar a ser poco legible -->
<!-- <hr class="line-error"
[class.valid]="nameInput4.valid"
[class.invalid]="nameInput4.invalid"> -->
<!-- Es mejor usar ...-->
<hr
class="line-error"
[ngClass]="{
'valid':nameInput4.valid,
'invalid':nameInput4.invalid
}"
/>
<p class="message-error" [class.invalid]="nameInput4.invalid">
El campo es requerido
</p>
<h2>Ng Style</h2>
<div class="styles">
<div>
<input type="number" [(ngModel)]="box.width" />
<input type="number" [(ngModel)]="box.height" />
<input type="color" [(ngModel)]="box.background" />
</div>
<div>
<div
[ngStyle]="{
'width.px':box.width,
'height.px':box.height,
'background-color':box.background,
'display': 'block'
}"
></div>
</div>
</div>
box = {
width: 100,
height: 100,
background: "red",
};
Creando un formulario
<h2>Formulario</h2>
<form (ngSubmit)="onRegister()" #myForm="ngForm">
<div class="input.group">
<label for="name">Nombre</label>
<input
required
name="name"
type="text"
id="name"
[(ngModel)]="register.name"
/>
<p>Mensajes de error</p>
</div>
<div class="input.group">
<label for="email">Email</label>
<input
required
name="email"
type="text"
id="email"
[(ngModel)]="register.email"
/>
<p>Mensajes de error</p>
</div>
<div class="input.group">
<label for="password">Password</label>
<input
name="password"
required
type="text"
id="password"
[(ngModel)]="register.password"
/>
<p>Mensajes de error</p>
</div>
<button [disabled]="myForm.invalid" type="submit">Registrar</button>
<!-- Si hay otro boton que hace otra cosa que no sea enviar el formulario hay que ponerle un type="button", sino angular lo toma como si fuera un type="submit" -->
<button type="button">Action</button>
</form>
register = {
name: '',
email: '',
password: '',
};
onRegister() {
console.log(this.register);
}
}
Estructura de ficheros en Angular
Archivos de configuración
- tsconfig.spec.json es el archivo de testing
- tsconfig.json es donde están las configuraciones de typescript
- tsconfig.app.json extiende del archivo anterior.
- package.json se encuentran los scripts que se pueden usar, dependencias, etc.
- angular.json se pueden indicar reglas como en donde se guardará el proyecto cuando se haga el build
- outputPath es el directorio final.
- styles aqui se puede agregar bootstrap.
- budgets se puede indicar cuanto se quiere que ocupe la aplicación como mínimo y máximo.
La carpeta src
- styles.css es el fichero de estilos global.
- main.ts es el encargado de levantar la aplicación
- index.html es donde Angular inyecta todo el código que se genere
La carpeta app
- Es donde se crean los componentes, servicios, etc.
- app.component.html es el segundo archivo html principal de la aplicación.
- app.component.ts es el archivo asociado al html, es donde se escribe la lógica
- app.module.ts es el módulo principal de la aplicación.
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
@NgModule({
declarations: [AppComponent], //Se pueden declarar otros componentes que no tengan modulo propio
imports: [BrowserModule, AppRoutingModule], //Se puede inyectar otros modulos
providers: [], //Se puede inyectar servicios
bootstrap: [AppComponent], //Es el componente inicial que se lanza en la aplicación
})
export class AppModule {}
La carpeta assets
- Se puede tener imagenes, fuentes.
La carpeta environments
- Los ficheros se los usa para crear variables en la aplicación, como por ejemplo una url de una api
Componentes
¿Qué es un componente en Angular?
Un componente básicamente es markup, meta-data y clase, todo esto combinado crea una UI (User Interface).
Crear componente con la cli de Angular
<nombre> es el nombre del componente
ng g c <button>
Inyectar un componente
//archivo button.component.ts
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-button", //Nombre de la etiqueta del componente
templateUrl: "./button.component.html", //Ruta del contenido html del componente
styleUrls: ["./button.component.css"], //Ruta de los estilos del componente
})
export class ButtonComponent implements OnInit {
//Lógica del componente
constructor() {}
ngOnInit(): void {}
}
Se lo inyecta al archivo app.component.html de la siguiente manera
<!--archivo app.component.html-->
<app-button></app-button>
One way data binding
Interpolación {{angular}}
Permite colocar texto entre elementos html y atributos
title: string = "tutorial";
url: string = "https://www.placeimg.com/300/400";
<p>{{title}} para aprender Angular</p>
<p>Total: {{5+5}}</p>
<img src="{{url}}" alt="" />
Two way data binding
Enlace de datos bidireccional
Se hace uso de NgModel quien crea una instancia del form-control, entonces se lo importa en el archivo app.module.ts
//app.module.ts
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [FormsModule],
})
//app.component.ts
//También puede ser cualquier otro componente el archivo
name!: string;
<!--app.component.html-->
<p>El nombre es: {{name}}</p>
<input type="text" [(ngModel)]="name" />
¿String Interpolation o Property [Binding]?
Recomendación
String Interpolation se lo usar para ingresar contenido como en un párrafo, h1 en donde se lo necesite reenderizarlo.
Property [Binding] es especificamente para propiedades de las etiquetas HTML
Nota: Si se están usando Objetos es más recomendable usar Property Binding
Directivas
¿Qué es una directiva?
Las directivas son como atributos que pueden cambiar la apariencia o el comportamiento del DOM element.
Tipos de directivas
- Estructurales
- De atributos
- Directivas Customs
- Componentes - Son directivas con template
*ngFor - Directiva estructural
cities = ["Barcelona", "Madrid", "Lima"];
<ul>
<li *ngFor="let city of cities">{{city}}</li>
</ul>
*ngIf - Directiva estructural
//app.component.ts
//También puede ser cualquier otro componente el archivo
name!: string;
<!--app.component.html-->
<p *ngIf="name ">El nombre es: {{name}}</p>
<input type="text" [(ngModel)]="name" />
Directivas de atributos
Formas de agregar estilos con ngClass, ngStyle
.selected {
background-color: rebeccapurple;
color: white;
padding: 1rem;
}
.unSelected {
background-color: white;
color: black;
}
.red {
color: red;
}
<ul>
<!-- ngClass -->
<!-- Primer forma -->
<li *ngFor="let city of cities" [ngClass]="['selected','red']">{{city}}</li>
<!-- Segunda forma -->
<li *ngFor="let city of cities" [ngClass]="'selected red'">{{city}}</li>
<!-- Tercer forma -->
<li *ngFor="let city of cities" [ngClass]="{'selected':true}">{{city}}</li>
<!-- Con un poco de dinamismo -->
<li
*ngFor="let city of cities"
[ngClass]="{'selected':city === 'Lima', 'red':city !== 'Barcelona'}"
>
{{city}}
</li>
<!-- ngStyle -->
<li
*ngFor="let city of cities"
[ngStyle]="{'color':'red', 'background':city==='Madrid'? 'blue':'green'}"
>
{{city}}
</li>
<!-- Es como poner estilos en línea, no muy recomendado -->
</ul>
Ciclo de vida de un componente
Un componente tiene un ciclo de vida que comienza cuando Angular crea una instancia de la clase de componente y representa la vista del componente junto con sus vistas secundarias.
El ciclo de vida continúa con la detección de cambios, ya que Angular verifica cuándo cambian las propiedades vinculadas a los datos y actualiza tanto la vista como la instancia del componente según sea necesario.
El ciclo de vida finaliza cuando Angular destruye la instancia del componente y elimina su plantilla renderizada del DOM.
Las directivas tienen un ciclo de vida similar, ya que Angular crea, actualiza y destruye instancias en el curso de la ejecución.
Interfaces que se ejecutan durante el ciclo de vida de un componente
Las tres interfaces mas importantes
ngOnChanges(changes: SimpleChanges): void {
console.log('Change->', changes);
// Trae los cambios anteriores y los nuevos
// Se los ve con los inputs, outputs
}
ngOnInit(): void {
console.log('OnInit->');
// Se ejecuta si no hay inputs u outputs
// Se lo usa para consumir API
}
ngOnDestroy(): void {
console.log('Destroy');
// Se utiliza para la desuscripcion de los observables y cuando el usuario va a abondar el componente
}
Event binding
¿Qué es?
Para vincular a un evento, utiliza la sintaxis de vinculación de eventos Angular.
Esta sintaxis consta de un nombre de evento de destino entre paréntesis a la izquierda de un signo igual y una declaración de plantilla entre comillas a la derecha. En el siguiente ejemplo, el nombre del evento de destino es click y la instrucción de la plantilla es onSave().
Nos permite escuchar y responder a acciones del usuario, como por ejemplo: pulsasiones de teclas, movimientos del mouse, clicks.
/* app.component.css */
.selected {
background-color: rebeccapurple;
color: white;
padding: 1rem;
}
.unSelected {
background-color: white;
color: black;
}
.red {
color: red;
}
//app.component.ts
name!: string;
selection!: string;
cities = ["Barcelona", "Madrid", "Lima"];
onCityClicked(city: string):void{
console.log("City ->", city);
this.selection = city;
}
onClear():void{
this.selection = "";
}
<!--app.component.html-->
<ul>
<li
*ngFor="let city of cities"
(click)="onCityClicked(city)"
[ngClass]="{'selected':city===selection}"
>
{{city}}
</li>
</ul>
<div *ngIf="selection">
<p>Your city is: {{selection}}</p>
<button (click)="onClear()">Clear your selection</button>
</div>
Event Binding
<!--Archivo app.component.html-->
<h1>Eventos</h1>
<button [disabled]="btnDisabled">Enviar</button>
<button (click)="toggleButton()">Toggle Button</button>
<br />
<button (click)="increaseNumber()">Number ++</button>
<p>Number: {{thing.number}}</p>
//Archivo app.component.ts
import { Component } from "@angular/core";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.scss"],
})
export class AppComponent {
img = "https://placeimg.com/200/200/any";
name = "Gabriel";
number = 12;
btnDisabled = true;
thing = {
name: "Gabriel",
number: 21,
img: "https://placeimg.com/200/200/any",
};
//Puede ser public o private, pero si se lo quiere usar en el componente debe ser public (por defecto)
toggleButton() {
this.btnDisabled = !this.btnDisabled;
}
increaseNumber() {
this.thing.number += 1;
}
}
Otros eventos que escuchar
- Keyup, Scroll
<!--Archivo app.component.html-->
<div class="box" (scroll)="onScroll($event)">
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Voluptatibus
quidem incidunt adipisci quod saepe non. Ratione tempore incidunt et, quo
eaque illo accusantium neque eveniet necessitatibus qui, consectetur
eligendi vel. Lorem ipsum dolor sit amet consectetur adipisicing elit.
Temporibus earum distinctio laboriosam unde porro dicta iure nam deleniti
animi, officia, ad at odit repellendus provident error numquam eaque
tempore! Maxime!
</p>
</div>
<p>Nombre {{thing.name}}</p>
<input type="text" [value]="thing.name" (keyup)="changeName($event)" />
//Archivo app.component.scss
.box {
height: 200px;
width: 200px;
overflow: auto;
background-color: rebeccapurple;
color: white;
}
//Archivo app.component.ts
import { Component } from "@angular/core";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.scss"],
})
export class AppComponent {
img = "https://placeimg.com/200/200/any";
name = "Gabriel";
number = 12;
btnDisabled = true;
thing = {
name: "Gabriel",
number: 21,
img: "https://placeimg.com/200/200/any",
};
// Otros eventos
onScroll(event: Event) {
const element = event.target as HTMLElement;
console.log(element.scrollTop);
}
changeName(event: Event) {
const element = event.target as HTMLInputElement;
console.log(element.value);
this.thing.name = element.value;
}
}
¿Qué es un decorador?
Un decorador es un tipo especial de declaración que se puede adjuntar a una clase, método, descriptor de acc.
Decorador @Input()
El decorador @Input() en un componente (o directiva) hijo significa que la propiedad puede recibir su valor
Como ejemplo se crea un componente llamado button
ng g c button
<!--app.component.html-->
<ul>
<li
*ngFor="let city of cities"
(click)="onCityClicked(city)"
[ngClass]="{'selected':city===selection}"
>
{{city}}
</li>
</ul>
<div *ngIf="selection">
<p>Your city is: {{selection}}</p>
<!-- <button (click)="onClear()">Clear your selection</button> -->
<!-- Se inyecta el componente creado -->
<app-button
(click)="onClear()"
[color]="'red'"
[label]="'Clear your selection'"
></app-button>
</div>
//button.component.ts
@Component({
selector: "app-button",
template: `<button [ngStyle]="{ 'background-color': color }">
{{ label }}
</button>`,
styleUrls: ["./button.component.css"],
})
export class ButtonComponent implements Onchanges, OnInit, OnDestroy {
@Input() color!: string;
@Input() label!: string;
constructor() {}
ngOnChanges(changes: SimpleChanges): void {
console.log("Changes->", changes);
}
ngOnInit(): void {
console.log("OnInit");
}
ngOnDestroy(): void {
console.log("OnDestroy");
}
//Para ver el ciclo de vida, abrir la consola del inspector de elementos
}
Decorador @Output()
El decorador @Output () en un componente (o directiva) hijo permite que los datos fluyan del hijo al padre.
Como ejemplo se crea un componente llamado form-new-item
ng g c form-new-item
//app.component.ts
name!: string;
selection!: string;
cities = ["Barcelona", "Madrid", "Lima"];
addNewCity(city:string):void {
this.cities.push(city);
}
onCityClicked(city: string):void{
console.log("City ->", city);
this.selection = city;
}
onClear():void{
this.selection = "";
}
<!--app.component.html-->
<app-form-new-item
(newItemEvent)="addNewCity($event)"
[label]="'City'"
[className]="'btn-info'"
></app-form-new-item>
<ul>
<li
*ngFor="let city of cities"
(click)="onCityClicked(city)"
[ngClass]="{'selected':city===selection}"
>
{{city}}
</li>
</ul>
<div *ngIf="selection">
<p>Your city is: {{selection}}</p>
<!-- <button (click)="onClear()">Clear your selection</button> -->
<app-button
(click)="onClear()"
[color]="'red'"
[label]="'Clear your selection'"
></app-button>
</div>
<!--form-new-item.component.html-->
<form>
<label for="newItem">New {{label}}</label>
<!-- template variable -->
<input type="text" id="newItem" #newItem />
<button
(click)="onAddNewItem(newItem.value)"
type="button"
[ngClass]="[className]"
>
Add {{label}}
</button>
</form>
// form-new-item.component.ts
import { Component, Input, OnInit, Output, EventEmitter } from "@angular/core";
@Component({
selector: "app-form-new-item",
templateUrl: "./form-new-item.component.html",
styleUrls: ["./form-new-item.component.css"],
})
export class FormNewItemComponent {
@Input() className!: string;
@Input() label!: string;
@Output() newItemEvent = new EventEmitter<string>();
onAddNewItem(item: string): void {
console.log("Item", item);
this.newItemEvent.emit(item);
}
}
Cabe destacar que cuando usamos el decorador @Input se utiliza [ ] para indicarle al componente hijo el valor que se esta pasando, en cambio el decorador @Output utiliza ( ) para capturar el valor emitido y pasrselo al metodo que tiene el componente padre.
Pipes
Los pipes son una herramienta de Angular que nos permite transformar visualmente la información, por ejemplo, cambiar un texto a mayúsculas o minúsculas, o darle formato de fecha y hora. Los pipes reciben un dato, y pueden transformar ese dato. Entonces, se puede decir que su cometido principal es transformar data.
Los pipes pueden ser puros o impuros
De forma predeterminada, los pipes, se definen como puros, de modo que Angular ejecuta el Pipe solo cuando detecta un cambio puro en el valor de entrada. Mientras que los pipes que son impuros cada vez que se ejecuta el ciclo de detección de cambios en angular, el volverá a transformar esa data aunque esa data no haya cambiado.
Pipes propios de Angular
Ejemplo:
<p>{{'6/1/15, 9:03 AM' | date:'full'}}</p>
<p>My birhtday: {{'6/1/15, 9:03 AM' | date:'short' | uppercase}}</p>
<p>My birhtday: {{'99' | currency:'EUR' }}</p>
<p>My birhtday: {{'99' | currency:'ARG' }}</p>
Pipes personalizados
Ver documentación:
ng g pipe filter
//filter.ts
import { Pipe, PipeTransform } from "@angular/core";
@Pipe({
name: "filter",
})
export class FilterPipe implements PipeTransform {
transform(value: string[], arg: string): string[] {
let result: string[] = [];
for (const value of values) {
if (value.indexOf(arg) > -1) {
result = [...result, value];
}
}
return result;
}
}
<!--app.component.ts-->
<input type="text" [(ngModel)]="criterio" />
// app.component.ts
export class AppComponent {
criterio = "";
}