Angular 21 de Cero a Experto / Signals a fondo
Inputs como señales y model(): comunicación reactiva
En el módulo anterior usaste input() para recibir datos del padre. Ahora que dominas las
señales, entiendes lo que realmente son: un input ES una señal de solo lectura. Eso
desbloquea cosas poderosas —derivar de un input con computed, reaccionar con effect,
transformar el valor al entrar— y hace obsoleto el viejo ngOnChanges. Hoy exprimes los
signal inputs y model(), el two-way binding reactivo.
Un input es una señal que viene de fuera
input(), input.required() y valores por defecto
import { Component, input } from '@angular/core';
@Component({
selector: 'app-tarjeta-gasto',
template: `<h3>{{ nombre() }}</h3><span>{{ valor() }}</span>`,
})
export class TarjetaGastoComponent {
nombre = input.required<string>(); // obligatorio: el compilador exige pasarlo
valor = input(0); // opcional, por defecto 0
moneda = input('COP'); // el tipo se infiere: string
}input.required<T>() no tiene valor inicial: Angular garantiza en compilación que el padre
lo pasa, así que dentro nunca es undefined. input(defecto) infiere el tipo del valor por
defecto. Ambos devuelven señales de solo lectura: las lees con (), pero no tienen .set()
—el padre es quien las cambia—.
Derivar y reaccionar a un input (adiós ngOnChanges)
Como el input es una señal, puedes construir computed y effect sobre él con total
naturalidad:
import { Component, input, computed, effect } from '@angular/core';
@Component({ selector: 'app-tarjeta-gasto', template: `...` })
export class TarjetaGastoComponent {
valor = input.required<number>();
// derivado del input: se recalcula solo cuando el padre cambia 'valor'
conIva = computed(() => Math.round(this.valor() * 1.19));
constructor() {
// reacciona a cambios del input SIN ngOnChanges
effect(() => console.log('El valor cambió a', this.valor()));
}
}Aquí está el paralelo legacy→moderno más útil de este tema:
Transformar el valor de entrada
input() admite una transformación que normaliza el valor al entrar —útil para coerción:
import { input, numberAttribute, booleanAttribute } from '@angular/core';
export class Ej {
// el padre puede pasar "42" (string de un atributo) y aquí llega como number
valor = input(0, { transform: numberAttribute });
// "" o presencia del atributo → true
activo = input(false, { transform: booleanAttribute });
// transform propio
nombre = input('', { transform: (v: string) => v.trim().toUpperCase() });
}model(): two-way binding reactivo
model() crea una señal que el hijo puede LEER y ESCRIBIR, y cuyos cambios el padre recibe
automáticamente. Es la base para componentes de formulario reutilizables:
import { Component, model } from '@angular/core';
@Component({
selector: 'app-campo-monto',
template: `
<button (click)="monto.set(monto() - 500)">−</button>
<span>{{ monto() }}</span>
<button (click)="monto.set(monto() + 500)">+</button>
`,
})
export class CampoMontoComponent {
monto = model(0); // señal de lectura Y escritura, sincronizada con el padre
}
// El padre: <app-campo-monto [(monto)]="presupuesto" />
// Cuando el hijo hace monto.set(...), la señal 'presupuesto' del padre se actualiza.A diferencia de input() (solo lectura), model() sí tiene .set() y .update(), y su
sintaxis en el padre es la "banana en caja" [(monto)]. Úsalo cuando el hijo necesite
proponer cambios al padre —un control de cantidad, un campo de texto, un toggle—.
Practica la lógica reactiva en vivo
Los inputs de Angular no corren en el sandbox, pero su ESENCIA —una señal externa de la que
derivas— sí. Con tu mini-sistema de señales, simula un input valor que "el padre" cambia,
y un derivado conIva que reacciona:
¿Qué reemplaza a `ngOnChanges` cuando quieres reaccionar a cambios de un `input()` señal?
Mini-reto
En el playground: 1) haz un valorInput (señal) y un presupuestoInput (señal); 2) crea un
computado saldo = presupuesto - valor; 3) simula que "el padre" cambia ambos inputs con
varios set y verifica que saldo se recalcula en cada caso. Luego, en tu cabeza, escribe
cómo se vería esto como un componente Angular con dos input() y un computed().
Qué sigue
Dominas los inputs reactivos. Quedan dos herramientas avanzadas de señales: linkedSignal
(un estado derivado que TAMBIÉN puedes escribir) y resource() (para cargar datos async de
forma declarativa, con estados de carga/error como señales). La próxima lección las cubre y
cierra la teoría de este módulo.