简体   繁体   中英

Cannot pass data from Parent to Child component

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());

There's a couple things wrong with your current implementation:

  • In your Parent component, courses is an array (I assume) not an observable - no need to use the async pipe
  • In your Child component you've named the input field data , and used a setter to call .next on a variable that should be an array - ie .next wont exist.

The below should fix your current implementation

Parent Comp

<child-component
    [courses]="courses" 
>
</child-component>

courses: any;

this.service.listCourses().subscribe((course: Course) => {
  this.courses = course;
});

Child Comp

@Input() courses: any;

It's important to note that listCourses is asynchronous

What 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)
    ]);
}

Comments

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 the onInit or afterViewInit

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM