1

In Angular 7, I'm passing arrays of person objects from the parent component to the child component. In the parent component the data is retrived by calling the rest endpoint of a user id list:

....forEach(userId => {
   this.api.getUser(userId).subscribe((personDto: PersonDTO) => { 
   this.personList.push(personDto);
  }
}

When the child component is loaded the full person list is not retrieved yet. Therefore I defined an BehaviourSubject in the Child Component.

Parent component:

<app-child-component [data]="personList"></app-child-component>

Child component:

private _data = new BehaviorSubject<PersonDTO[]>([]);

@Input()
set data(value: PersonDTO[]) {
   this._data.next(value);
};

get data() {
   return this._data.getValue();
}

ngOnInit() {
   console.log(this.data);
}

In the ngOnInit function in my child component I expect to get an array of PersonDto's. In the console I can see that I get the correct expected list of persons. But the problem is that the output in the console looks like this:

 []
 0 Object { id: 1, username: "John", ... }
 1 Object { id: 2, username: "Peter", ... }
 length: 2
 <prototype>: []

It has allways an array where the first element is [] an in this elment I can see the array with the correct values. ​ I think the [] comes from my initialization:

private _data = new BehaviorSubject<PersonDTO[]>([]);   
 

How can I get the array that it only contains the 2 values? I already tried with this.data[0]. But then I get an undefined. Any ideas?

8
  • That doesnt look like empty array first. It is depicting the array and its 2 elements. Length also says 2. 0 index object with 'John' and 1st index 'Peter' Commented Mar 13, 2021 at 16:43
  • With this.data.length i get 0. Any ideas how i can get the values? Commented Mar 13, 2021 at 16:48
  • where are you console logging this.data.length and this.data[0]? Commented Mar 13, 2021 at 16:52
  • In the function ngOnInit Commented Mar 13, 2021 at 16:55
  • This is because of the behavior subject Commented Mar 13, 2021 at 17:00

1 Answer 1

3

Your code calls set data of the child only once with this.personList of the parent. Afterwards, the same array is modified by the subscribe callback, but since it is the same array, set data is not called again. You could check this with a log output in set data. Angular's change detection updates the view when the array changes. So your code in the child should be working but is unnecessarily complicated.

First, you can bundle the getUser() calls:

const observables = userIds.map(userId => this.api.getUser(userId));
forkJoin(observables).subscribe((personDTOs: PersonDTO[]) => this.personList = personDTOs);

Furthermore, you can ditch this.personList of the parent and work directly with the observable:

const observables = userIds.map(userId => this.api.getUser(userId));
this.personList$ = forkJoin(observables);
<app-child-component [data]="personList$ | async"></app-child-component>

Since the async pipe will initially evaluate to null before the requests are completed you can make child component render conditionally:

<ng-container *ngIf="(personList$ | async) as personList">
  <app-child-component [data]="personList"></app-child-component>
</ng-container>

The child component needs a simple input field:

@Input() data: PersonDTO[];

in the child ngOnInit() data has already been assigned with the result of the getUser requests.

Sign up to request clarification or add additional context in comments.

3 Comments

In the Parent component i added as member variable: public personList$: Observable<PersonDTO[]> . In my ngOnInit in the Child component the variable this.data with your suggested changes is null. This means an Observable is passed to my Child component. Any ideas what could be missing?
When i call this.data in the ngonchanges livecycle then i get the result
I'm sorry, the async pipe sends null as the first value, and only after the requests completed sends the array. I edited my answer to provide a solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.