Using Angular version 11.0.2
I am encountering issues with the async
pipe inside an ngIf
template, where my data is not being properly refreshed. To illustrate this problem, I have created a simplified example.
To reproduce the issue:
- Click on the
add
button multiple times - Click on the
toggle
button - The
data$ | async
displays thedefaultValue
instead of the actual values frommyArray
(not the expected behavior) - Click on the
add
button again - The
data$ | async
is refreshed and now displays the correctmyArray
values (expected behavior) - Toggle the
showMe
state two times - The
data$ | async
displays thedefaultValue
once more (unexpected behavior)
It seems that ngIf
is storing the initial values of data$
during the first ngOnInit
. Why does {{data$ | async | json}}
return the default value even when myArray
has been updated?
How can I handle this scenario using rxjs
and ngIf
?
Template:
<button (click)="add()">+ add</button>
<button (click)="sub()">- sub</button>
<button (click)="toggle()">toggle</button>
myArray={{myArray.value | json}}
length={{myArray.length}}
<div *ngIf="showMe">
Inside ngIf:<br>
data={{data$ | async | json}}<br>
myArray={{myArray.value | json}}
</div>
Component:
import { Component, OnInit,ChangeDetectorRef } from "@angular/core";
import { FormArray, FormBuilder } from "@angular/forms";
import { combineLatest, Observable, of } from "rxjs";
import { filter, map, startWith, tap } from 'rxjs/operators';
@Component({
selector: "my-app",
templateUrl: "src/app.component.html"
})
export class AppComponent implements OnInit{
showMe = false;
form: FormGroup;
x: number = 0;
data$: Observable<any>;
constructor(
private fb: FormBuilder,
private cd: ChangeDetectorRef
) {}
ngOnInit() {
this.form = this.fb.group({
myArray: this.fb.array(['defaultValue'])
}) ;
this.data$ = this.myArray.valueChanges.pipe(startWith(this.myArray.value));
}
add() {
this.myArray.push(this.fb.control(this.x++));
}
sub() {
this.myArray.removeAt(this.myArray.length - 1);
}
toggle() {
this.showMe = !this.showMe;
}
get myArray(): FormArray {
return this.form.get('myArray') as FormArray;
}
}