Reputation: 87
I am trying to capture user inputs and perform some business logic depending upon the inputs and bind the resulting data back to the form element. I hook into form valuechanges observable and perform my custom logic and bind the result to template.
I am trying to avoid subscribing from component and do it from template using async pipe as shown below. But if I am not subscribing from the component, logic is not triggering.
From my understanding since async pipe will subscribe to the observable, from component the pipe operation logic should work fine but is is not getting called unless I do another subscribe as shown below, can any one help me why it is not triggering the pipe operator logic since I already subscribed using async pipe in the template, please ? Thanks.
I tried moving the logic to ngAfterViewChecked hook still not working, if I subscribe from component it is working but I want to avoid multiple subscription.
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Observable } from 'rxjs';
import { tap, startWith } from 'rxjs/operators';
@Component({
selector: 'app-check-value-changes',
templateUrl: './check-value-changes.component.html',
styleUrls: ['./check-value-changes.component.scss']
})
export class CheckValueChangesComponent implements AfterViewInit {
@ViewChild('form') form: NgForm;
valueChanges$: Observable<any>;
ngAfterViewInit() {
this.valueChanges$ = this.form.valueChanges;
// Not Working
this.valueChanges$.pipe(
tap((c) => console.log(`Async pipe Subscribe ? - ${JSON.stringify(c)}`))
// other business logic here
);
// Working fine
this.valueChanges$.pipe(
tap((c) => console.log(`Explicit Subscribe - ${JSON.stringify(c)}`))
// other business logic here
).subscribe();
}
}
<span *ngIf="valueChanges$ | async as value">
{{ value | json }}
</span>
<form #form="ngForm">
<input type="text" name="txtName" ngModel>
</form>
Upvotes: 1
Views: 2501
Reputation: 87
Turns out to be a simple fix, when I combined the observable initialization and pipe operation statements together in a single line everything works fine.
In my original code even though I did my pipe operation in valueChanges$ observable I didn't mutate the original observable and eventually created another observable which of-course needs another subscription to emit the values.
Fixed component code :
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Observable, Subject } from 'rxjs';
import { tap } from 'rxjs/operators';
@Component({
selector: 'app-check-value-changes',
templateUrl: './check-value-changes.component.html',
styleUrls: ['./check-value-changes.component.scss']
})
export class CheckValueChangesComponent implements AfterViewInit {
@ViewChild('form') form: NgForm;
valueChanges$: Observable<any>;
ngAfterViewInit() {
this.valueChanges$ = this.form.valueChanges.pipe(
tap((c) => console.log(`Async pipe Subscribe ? - ${JSON.stringify(c)}`))
);
}
}
Upvotes: 2