CodeForge

Angular 21 de Cero a Experto / Fundamentos

Templates y binding: el puente entre la clase y la pantalla

Teoría22 min20 XP

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:

interpolacion.ts
@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 [ ]:

property.ts
@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:

event.ts
@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 ( ):

two-way.ts
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.