Angular 21 de Cero a Experto / Fundamentos
Templates y binding: el puente entre la clase y la pantalla
Un componente sin binding es un molde vacío. El binding es el sistema que conecta tu clase
con el HTML en las dos direcciones: mostrar datos en la pantalla y recibir acciones del
usuario. En React todo esto vivía dentro de {} en el JSX; Angular tiene una sintaxis
dedicada —dobles llaves, corchetes y paréntesis— que dice de un vistazo QUÉ tipo de enlace
es cada uno. Hoy la dominas por completo.
Cuatro flechas, cuatro sintaxis
Interpolación: mostrar un valor
La forma más simple. Dobles llaves insertan el valor de una expresión de la clase como texto:
@Component({
template: `
<h2>{{ titulo }}</h2>
<p>Total: {{ total }} COP</p>
<p>Con IVA: {{ total * 1.19 }}</p> <!-- puedes poner expresiones -->
`,
})
export class ResumenComponent {
titulo = 'Mi Bolsillo';
total = 85000;
}Es el equivalente exacto de {titulo} en JSX. Dentro de {{ }} puedes poner expresiones
(sumas, llamadas a métodos, ternarios), pero NO sentencias: es para PRODUCIR un valor a
mostrar, no para ejecutar lógica.
Property binding: enlazar una propiedad del DOM
Para pasar un valor a una propiedad de un elemento o componente, usa corchetes [ ]:
@Component({
template: `
<img [src]="urlAvatar" [alt]="nombre" />
<button [disabled]="cargando">Guardar</button>
<app-tarjeta-gasto [valor]="montoCafe" />
`,
})
export class EjemploComponent {
urlAvatar = '/avatar.png';
nombre = 'Miguel';
cargando = true;
montoCafe = 4500;
}La diferencia con la interpolación: {{ }} siempre produce un STRING para el contenido de
texto; [prop]="expr" pasa el VALOR REAL (un booleano, un número, un objeto) a la propiedad.
Por eso [disabled]="cargando" funciona con un booleano de verdad, mientras que
disabled="{{ cargando }}" pasaría el string "true". Regla: para datos que no son texto,
usa corchetes.
Event binding: escuchar al usuario
Para reaccionar a un evento, usa paréntesis ( ) con el nombre del evento del DOM:
@Component({
template: `
<button (click)="incrementar()">Sumé un gasto</button>
<input (input)="onEscribir($event)" />
<p>Llevas {{ cuenta }} gastos</p>
`,
})
export class ContadorComponent {
cuenta = 0;
incrementar() {
this.cuenta++; // cambiar una propiedad → Angular repinta la vista
}
onEscribir(evento: Event) {
const input = evento.target as HTMLInputElement;
console.log(input.value);
}
}Compáralo con React: allá era onClick={incrementar} (camelCase, pasas la función);
aquí es (click)="incrementar()" (con paréntesis, escribes la LLAMADA). El $event es la
variable mágica del template que contiene el objeto del evento —como el e que recibías en
los manejadores de React—.
Two-way binding: la "banana en caja"
A veces quieres que un input y una propiedad estén siempre sincronizados: si el usuario
escribe, la propiedad cambia; si la propiedad cambia, el input se actualiza. Eso es
two-way binding, y su sintaxis [(ngModel)] combina un property binding [ ] con un event
binding ( ):
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
imports: [FormsModule], // ngModel vive en FormsModule
template: `
<input [(ngModel)]="nombreGasto" />
<p>Escribiste: {{ nombreGasto }}</p>
`,
})
export class FormComponent {
nombreGasto = '';
}¿Por qué `[disabled]="cargando"` es distinto de `disabled="{{ cargando }}"`?
Mini-reto
En papel o en tu editor, escribe el template de un componente "agregar gasto" con: 1) un
<input> con two-way binding a una propiedad descripcion; 2) un <p> que muestre en vivo
lo que se escribe con interpolación; 3) un <button> con [disabled] enlazado a una
propiedad guardando y un (click) que llame a un método guardar(). Identifica en cada
línea hacia qué dirección fluye el dato.
Qué sigue
Ya muestras datos y escuchas eventos, pero un template real necesita decidir (mostrar esto
o aquello) y repetir (una tarjeta por cada gasto). La próxima lección es una de las joyas
de Angular moderno: el nuevo control flow @if / @for / @switch, y el gran salto desde
las viejas directivas *ngIf y *ngFor.