Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

angular 17 – How too use the new input with declartive with toSignal

I’m trying to use the new toSignal and input with the new angular 17.x. But when it comes to "input" i can only get the value on "OnInit" how can i solve this because I’m trying to filter the observable with the incoming value from input declarative.

Hope you guys understand what I mean.

  transferId = input.required<string>();
  progressSteamType = input.required<string>();
  progressBarHeightSmall = input<boolean>(true);

  progress$ = this._progressService.progress$;

  private _subs = new Subscription();
  progress = toSignal<IProgress | null>(this.progress$);

  ngOnInit(): void {
    this.progress$.pipe(
      filter(p => p.transferId.toLowerCase() === this.transferId()?.toLowerCase() && p.type === this.progressSteamType()) <--- this won't work because i already declared it above. The only way i can get the transferId is in ngOnit. because its an input
    )
  }

What I want to achieve is something like this. But this wont work. because transferId hasn’t initiated

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  progress$ = this._progressService.progress$.pipe(
    filter(p => p.transferId.toLowerCase() === this.transferId()?.toLowerCase() && p.type === this.progressSteamType())
  )

>Solution :

We can use effect to watch for new signal changes and trigger the pipe update! Only when transferId is available we trigger the update!

Then we take the effectRef which can be used to destroy the signal once we are done with updating the pipe, we can use effectRef.destroy() for this!

import { Component, effect, input } from '@angular/core';
import { Subscription, of, interval } from 'rxjs';
import { toSignal } from '@angular/core/rxjs-interop';
import { filter, map } from 'rxjs/operators';
import { CommonModule } from '@angular/common';
@Component({
  selector: 'app-child',
  standalone: true,
  imports: [CommonModule],
  template: `{{progress$ | async | json}}`,
})
export class ChildComponent {
  transferId = input.required<string>();
  progressSteamType = input.required<string>();
  progressBarHeightSmall = input<boolean>(true);

  progress$ = interval(1000).pipe(
    map(() => ({ transferId: 'test', type: 'qwerty' }))
  );

  private _subs = new Subscription();
  progress = toSignal<any | null>(this.progress$);

  constructor() {
    const effectRef = effect(() => {
      const transferId = this.transferId();
      if (transferId) {
        console.log('time to cleanup', transferId, this.progressSteamType());
        this.progress$ = this.progress$.pipe(
          filter(
            (p: any) =>
              p.transferId.toLowerCase() === transferId?.toLowerCase() &&
              p.type === this.progressSteamType()
          )
        );
        effectRef.destroy();
      }
    });
  }

  ngOnInit(): void {}
}

PARENT:

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { ChildComponent } from './app/child/child.component';

@Component({
  selector: 'app-root',
  imports: [ChildComponent],
  standalone: true,
  template: `
    <app-child [transferId]="'test'" [progressSteamType]="'qwerty'"/>
  `,
})
export class App {}

bootstrapApplication(App);

Stackblitz Demo

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading