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
progress$ = this._progressService.progress$.pipe(
filter(p => p.transferId.toLowerCase() === this.transferId()?.toLowerCase() && p.type === this.progressSteamType())
)
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 {}
}
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);