Issue
I am wondering what is wrong with my code here https://stackblitz.com/edit/angular-ivy-rc4fq8. I use widgetNameForm$ to pass to child component. Whereas switchMap should switch to valueChanges stream and emit value on input typing but such approach surprisingly does not work. Previously I used other code described bellow but it has nested subscription and I would like to stick with more reactive approach like described on stackblitz
this.widgetName$.subscribe(val => {
this.widgetNameForm = this.formBuilder.group({
name: [val, {validators: Validators.required}]
});
this.widgetNameForm.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(val => console.log('it emits value on typing', val));
})
Solution
You have 2 different subscriptions:
- one in constructor
- one in template via
async
pipe
Your problem is that each subscription will receive a separate instance of a FormGroup
. This means the instance you subscribe to in your controller is not what is being passed to the child component and bound to the form, therefore no valueChanges
are ever emitted.
You can resolve this by sharing a single subscription by using the shareReplay
operator:
this.widgetNameForm$ = this.widgetName$.pipe(
map(val => this.formBuilder.group({ name: [val, {validators: Validators.required}] })),
shareReplay() // <---
);
Check out this StackBlitz. Notice the "instance id" is shown in the input field. If you comment out the shareReplay()
line you can see that you end up with 2 instances; with it you get only one.