Reputation: 2420
From a parent component, I am passing the form array to the child component in this way.
<form class="form-horizontal" [formGroup]="myForm" (ngSubmit)="onSubmit()">
<hello [myForm]="myForm"></hello>
</form>
In the parent component .ts I have fetched the data from API and bind the result to the form array.
Form array is defined as:
this.myForm = this.fb.group({
frequency: [2, Validators.required],
memberid: this.fb.array([]),
});
In the ngOnInit() i have called the the function callApi():
async callApi() {
const fTitle = this.myForm.controls.memberid as FormArray;
const response = await fetch(this.url);
const json = await response.json();
let arr = [];
json.map((item) => arr.push(item.id));
arr.forEach((item) => fTitle.push(this.fb.control(item)));
console.log(this.myForm.value);
}
ngOnInit(){
this.callApi();
}
In the child component, I am trying to filter the memberList
with an memberid that is passed in the form group.
export class HelloComponent {
public memberScheduleNotifications = [];
public memberList = [
{ id: 2, name: 'a' },
{ id: 1, name: 'b' },
{ id: 3, name: 'c' },
{ id: 4, name: 'd' },
];
@Input() myForm: FormGroup;
ngOnInit() {
this.memberFilter();
}
memberFilter() {
const member = this.myForm.controls.memberid as FormArray;
this.memberScheduleNotifications = member.value || [];
this.memberList = this.memberList.map((x) =>
this.memberScheduleNotifications.find((y) => y == x.id)
? { ...x, selected: true }
: { ...x }
);
}
}
Component
@Component({
selector: 'hello',
template: `
<div class="form-group">
<p>child component</p>
<pre> {{memberList | json}}</pre>
</div>
`,
styles: [`h1 { font-family: Lato; }`],
})
Here the member list is not filtered with the member id passed from the parent component. The view is displayed without the filter being applied.
The child component not listening to the changes in the parent form array, which is updated through the API call.
What I am doing wrong here?
Upvotes: 1
Views: 4146
Reputation: 21
You can add this little hack in hello.component.html:
<ng-container *ngIf="myForm.valueChanges | async"></ng-container>
This async pipe will trigger change detection
Upvotes: 0
Reputation: 13317
Because you using changeDetection: ChangeDetectionStrategy.OnPush
, Angular is not running running change detection cycle, thus the latest data is not appearing in your app.component.html
or in child component.
I was not able to make ChangeDetectionRef
work with aync/await
, but I was curious if I can find a workaround to provide you a workable solution. I made it work with Angular's 'HttpClient'. I also added an *ngIf
check, so that child component doesn't load until data has been fetched from API. I also had to use ngOnChanges
instead of ngOnInit
in child component, to get the latest myForm
value from parent.
Hope this helps you to get on right track.
ChangeDetectionRef
and OnChanges
, after OP mentioned use of ChangeDetectionStrategy.OnPush
not necessary.app.component.html:
this.http.get(this.url).subscribe((data: Todo[]) => {
this.arrHttp = [];
const fTitle = this.myForm.controls.memberid as FormArray;
data.map((item) => this.arrHttp.push(item.id));
this.arrHttp.forEach((item) => fTitle.push(this.fb.control(item)));
this.ref.detectChanges();
});
app.component.html:
<hello *ngIf="arrHttp && arrHttp.length" [myForm]="myForm"></hello>
hello.component.ts:
ngOnChanges(changes: SimpleChanges) {
if (changes.myForm && changes.myForm.currentValue) {
this.myForm = changes.myForm.currentValue;
this.memberFilter();
}
}
memberFilter() {
const member = this.myForm.controls.memberid as FormArray;
this.memberScheduleNotifications = member.value || [];
this.memberList = this.memberList.map((x) =>
this.memberScheduleNotifications.find((y) => y == x.id)
? { ...x, selected: true }
: { ...x }
);
}
Result:
Upvotes: 0
Reputation: 1159
Your child component is not detecting the changes because you are pushing the memberlist into the FormArray, so for Angular is like you are not updating the reference you are sending to the child component.
To Angular detect the change in your child component you can:
Upvotes: 2