Do you have any idea about the strange problem below?
I am passing data from a parent to a child component that is returned from a service method returning data as Observable<DemoModel>
. But, when child component is loading, the data is undefined and it is only filled after ngAfterViewInit
(I also tried getting the data on this method, but the data is still undefined). So, I also tried to apply some ngOnchanges
approach, but the problem is much more related to that the data retrieved from Parent Component is not ready while Child Component is loading (I also tried to use async, etc. instead of subscribe. How should I get data to make it ready while child component is loading?
Parent and Child Components are shown below:
Parent Comp
<child-component
[courses]="courses|async"
>
</child-component>
courses: any;
this.service.listCourses().subscribe((course: Course) => {
this.courses = course;
});
Child Comp
private courses: any;
@Input()
set data(data: any) {
this.courses.next(data);
}
myControl = new FormControl('');
ngAfterViewInit() {
// >>> THIS THROWS ERROR AS this.courses is undefined
this.myControl.setValidators([
Validators.required,
forbiddenNamesValidator(this.courses)
]);
}
I also tried to use some *ngIf
in html, but as the this.courses
parameter is used in the methods, it does not make any sense to check the data in html.
The problem may be caused by subscribe method, but I also tried to use promise (I am not sure if I used it properly).
1st way: Add ngIf
to check whether you have data or not.
<child-component [courses]="courses" *ngIf="courses.length > 0"> </child-component>
2nd Way : If you want use async
then don't subscribe it in your component.
<child-component [courses]="courses$ | async" *ngIf="(courses$| async)?.length > 0"> </child-component>
Component:
courses$: Observable<any>;
this.courses$ = this.service.listCourses().pipe(shareReplay());
async
pipedata
, and used a setter to call .next
on a variable that should be an array - ie .next
wont exist.Parent Comp
<child-component
[courses]="courses"
>
</child-component>
courses: any;
this.service.listCourses().subscribe((course: Course) => {
this.courses = course;
});
Child Comp
@Input() courses: any;
listCourses
is asynchronousWhat this means is that courses
won't necessarily be guaranteed to have a value when ngAfterViewInit
is called and will likely then throw a similar error.
What I can suggest to solve this is the following:
<child-component
*ngIf="courses?.length"
[courses]="courses"
>
</child-component>
You won't then have to wait for ngAfterViewInit
, and instead can just wait for ngOnInit
.
ngOnInit(): void {
this.myControl.setValidators([
Validators.required,
forbiddenNamesValidator(this.courses)
]);
}
Passing a list from parent to child, should I use an observable/promise/array etc?
That's entirely up to you, I prefer using the async
pipe when dealing with observables, because then I don't need to worry about unsubscribing from my subscriptions.
<child-component
[courses]="courses | async"
>
</child-component>
courses = this.service.listCourses()
I think there is no need to use get/set for the courses in Child Component as the list will not be changed
You don't necessarily need to even use a get/set when engaging with data that changes. Angular will update the @Input
data for you, so you don't need worry about using a get/set unless you explicitly need that functionality.
Should I call the
this.myControl.setValidators([]}
and the filter method in theonInit
orafterViewInit
There's no need to shift setting the validator into your afterViewInit
, you don't need to wait for your Component's View to be initialized before you set the validator.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.