Angular v16 introduce el nuevo paquete rxjs-interop, que viene con una práctica función llamada toObservable que permite a los desarrolladores convertir una signal en un observable. En este artículo, exploraremos esta nueva función y cómo se puede utilizar.

En primer lugar, necesitamos importar la función toObservable del módulo @angular/core/rxjs-interop. Aquí hay un fragmento de código de ejemplo que demuestra su uso:

import { toObservable } from '@angular/core/rxjs-interop';
import { signal } from '@angular/core';

@Component({
  standalone: true,
  template: `
    <input (input)="value.set(input.value)" #input />
  `,
})
export class FooComponent {
  value = signal('');
  value$ = toObservable(this.value);

  ngOnInit() {
    this.value$.subscribe(console.log);
  }
}

Creamos una signal con un valor inicial de una cadena vacía, y luego usamos la función toObservable para convertirla en un observable. A continuación, nos suscribimos al observable y registramos su valor cada vez que cambia.

Bajo el capó, la función toObservable crea un ReplaySubject y envuelve la señal proporcionada en un efecto. Cuando el valor de la señal cambie, el efecto emitirá el nuevo valor.

Recuerda que si quieres aprender más de angular 16

Una ventaja de usar señales es que no necesitamos añadir el operador distinctUntilChanged, ya que el trabajo ya está hecho a nivel de señal. Además, si la señal lanza un error, se pasará como notificación de error al suscriptor.

Un efecto interesante de utilizar el efecto (😄) para emitir valores es que el valor se entregará de forma asíncrona. Esto significa que aunque emitamos varios valores en el mismo "tick", sólo recibiremos el último valor de la señal.

Es importante tener en cuenta que cuando se llama a la función toObservable, se comprueba que se está llamando en un contexto de inyección. Si no es así, se producirá un error. Esto significa que podemos utilizar la función toObservable sólo cuando la función inject() está disponible, excepto en los casos en que pasamos un inyector explícitamente.

@Component({
  standalone: true,
  template: `
    <input (input)="value.set(input.value)" #input />
  `,
})
export class FooComponent {
  value = signal('');
  private injector = inject(Injector);
 
  ngOnInit() {
    const value$ = toObservable(this.value, {
      injector: this.injector
    }).subscribe(console.log);
  }
}

Esto se debe a que Angular completará el ReplaySubject subyacente y destruirá el registro del efecto cuando se destruya el contexto envolvente. Lo hace utilizando el nuevo gancho OnDestroy que obtiene al utilizar la función inject().

Fuente