Codea Bien Logo
Grandes novedades en Angular 22
Angular

Grandes novedades en Angular 22

Kevin Dávila

angularsignalsangular 22

Si pensabas que Angular ya había alcanzado su pico de innovación con las versiones anteriores, prepárate. Angular 22 acaba de aterrizar y no es una actualización cualquiera. Es la versión que consolida el cambio de paradigma que empezó hace un par de años. Menos boilerplate, más reactividad nativa y, sobre todo, una experiencia de desarrollo mucho más fluida.

Aquí te cuento lo más importante que tienes que saber para no quedarte atrás.


Signal Forms estables

Llevábamos tiempo esperándolo y ya están aquí. Los formularios basados en Signals han salido de su fase experimental y ya son aptos para producción. Olvídate de lidiar con las limitaciones de los formularios reactivos tradicionales cuando quieres integrar signals.

Ahora puedes definir tus formularios con una sintaxis mucho más limpia y, lo mejor de todo, con tipado fuerte garantizado.

/**
 * Getting started with Signal Forms 
 **/
import {signal} from "@angular/core"
import {form} from "@angular/forms/signals"

@Component({
  selector: 'app-payment',
  imports: [FormField],
  templateURL: './app-payment.html',
})
class Payment {
  readonly paymentModel = signal({
    paymentType: '',
    amount: 0
  });
  readonly f = form(paymentModel,
    schema => {
      required(schema.paymentType, {
        message: 'Required field'
      });
    });
}
<!-- app-payment.html -->
<form>
  <section>
    <label for="payment-type">Payment Type:</label>
    
    <select id="payment-type" [formField]="f.paymentType">
      <option value="">Select a method...</option>
      <option value="credit">Credit Card</option>
      <option value="paypal">Payment Service</option>
    </select>

    @if (f.paymentType().invalid() && f.paymentType().touched()) {
      <p class="error">
         @for (error of f.paymentType().errors(); track error.kind) {
           <span>{{ error.message }}</span>
        }
      </p>
    }
    </section>

  <button type="submit" [disabled]="f().invalid()">Submit Payment</button>
</form>

La integración es total. Puedes leer valores, estados de validez y errores directamente como señales, lo que significa que Angular sabe exactamente qué parte de la UI actualizar sin mover un solo dedo de más.


Resource y httpResource: Data fetching sin dramas

Si alguna vez sentiste que usar un Effect para cargar datos de una API era como matar moscas a cañonazos, el nuevo API de resource es para ti. Ya es estable y cambia las reglas del juego.

resource te permite declarar de dónde vienen tus datos y qué dependencias tienen (como el ID de un usuario). Si la dependencia cambia, el recurso se refresca solo.

import { Component, signal, resource } from '@angular/core';

@Component({
  selector: 'app-product-detail',
  template: &#96;
    @if (productResource.isLoading()) {
      <p>Cargando producto...</p>
    } @else if (productResource.value(); as product) {
      <h1>{{ product.name }}</h1>
    }
  &#96;
})
export class ProductDetailComponent {
  productId = signal(123);

  // El recurso se refresca automáticamente si productId cambia
  productResource = resource({
    request: () => ({ id: this.productId() }),
    loader: async ({ request }) => {
      const response = await fetch(&#96;/api/products/&#36;{request.id}&#96;);
      return response.json();
    }
  });
}

Y si prefieres seguir usando HttpClient, tienes httpResource, que hace lo mismo pero integrado perfectamente con el ecosistema de servicios de Angular.


Inyección de dependencias asíncrona

¿Alguna vez has querido inyectar un servicio que tarda en cargarse o que quieres cargar bajo demanda? Con injectAsync, Angular 22 nos da una herramienta poderosa para el code-splitting.

import { Component, injectAsync } from '@angular/core';

@Component({
  selector: 'app-heavy-feature',
  template: &#96;<button (click)="loadService()">Cargar reporte pesado</button>&#96;
})
export class HeavyFeatureComponent {
  async loadService() {
    // Carga el servicio solo cuando realmente se necesita
    const AnalyticsService = await import('./analytics.service').then(m => m.AnalyticsService);
    const analytics = await injectAsync(AnalyticsService);
    
    analytics.trackEvent('Feature Loaded');
  }
}

Esto es oro puro para optimizar el tamaño inicial de tus bundles. No cargues lo que el usuario no va a usar de inmediato.


El nuevo decorador @Service

Adiós a escribir @Injectable({ providedIn: 'root' }) cada vez que quieres un singleton global. Angular 22 introduce el decorador @Service, que es más corto, más descriptivo y hace exactamente lo que esperas.

import { Service } from '@angular/core';

@Service()
export class AuthService {
  // Este servicio es un singleton global por defecto
  isAuthenticated = signal(false);
}

Es un cambio pequeño, pero de esos que hacen que el código se sienta mucho más moderno y menos "verboso".


Mejoras en los templates: Arrow functions y comentarios

Los templates de Angular están recibiendo mucho amor. Ahora puedes usar arrow functions directamente en tus bindings, lo que evita tener que crear métodos pequeños en el componente solo para una lógica de transformación mínima.

<!-- Ahora puedes hacer transformaciones simples así -->
<ul>
  @for (user of users(); track user.id) {
    <li>{{ ((u) => u.name.toUpperCase())(user) }}</li>
  }
</ul>

Además, ¡por fin tenemos comentarios reales en las etiquetas HTML! Puedes usar // o /* */ dentro de los tags para documentar bindings complejos.

<app-complex-chart
  [data]="results()" // Datos procesados del backend
  /* Estilo visual del gráfico */
  [theme]="selectedTheme()"
/>

OnPush por defecto: Rendimiento como estándar

A partir de Angular 22, la estrategia de detección de cambios OnPush es la predeterminada para las nuevas aplicaciones. El antiguo modo Default ahora se llama Eager.

Esto obliga a seguir mejores prácticas de rendimiento desde el día uno. Si usas signals, esto no te supondrá ningún problema; de hecho, es como Angular debería haber funcionado siempre. Tu aplicación será más rápida y eficiente sin que tengas que configurar nada extra.


Error Boundaries (Preview): Control de daños

¿Qué pasa si un componente falla estrepitosamente? Antes, podía romper toda la página. Con la nueva sintaxis de @boundary, puedes capturar errores a nivel de template de forma declarativa.

@boundary {
  <app-chart-complicado />
} @error (error) {
  <div class="error-panel">
    Lo sentimos, el gráfico no pudo cargarse. Error: {{ error.message }}
  </div>
}

Aunque está en preview, es una funcionalidad que acerca a Angular a patrones de resiliencia que ya veíamos en otros frameworks, pero con la elegancia sintáctica de Angular.


Conclusión

Angular 22 no se trata de reinventar la rueda, sino de perfeccionarla. Con Signal Forms estables, el API de Resource simplificando el data fetching y las mejoras en los templates, el framework se siente más ligero y potente que nunca.

Si todavía estás dudando en dar el salto a las Signals, esta versión es la señal que estabas esperando. Literalmente.


Keywords

  • Angular 22

  • Signal Forms

  • Angular Resource API

  • injectAsync Angular

  • Angular OnPush default

  • Error Boundaries Angular