Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 how to make child component wait for async data to be ready

Tags:

angular

I'm passing async data from a parent component to a child component. And the child component needs to know the length of the data in order to do something.

How the problem is that the child component can't use the 'Oninit' hook to do work because the data isn't available at this time. So how do I do this?

The parent component code looks like:

@Component({     moduleId: module.id,     selector: 'parent',     template: `<div>                     <child [items]="items | async">                 </div>` })  export class Parent implements OnInit {      items: Items[];      constructor(         private itemService: ItemService,         private router: Router     ) { }          ngOnInit() {         this.itemService.getItemss()             .subscribe(                 items => this.items = items,                 error => this.errorMessage = <any>error             );     }  } 

And the child component looks like:

@Component({     moduleId: module.id,     selector: 'child',         template: `<div>                     <div *ngFor="let itemChunk of itemChunks"></div>                     content here                 </div>` }) export class child implements OnInit{     @Input() items: Items[];     itemChunks: Items[][];      ngOnInit() {         this.itemChunks = this.chunk(this.Items);     }      chunk(items: Items[]) {         let result = [];         for (var i = 0, len = items.length; i < len; i += 6) { // this line causes the problem since 'items' is undefined             result.push(items.slice(i, i + 6));         }         return result;     } } 

What is the best practice to handle this?

like image 514
Allen Zhang Avatar asked Dec 30 '16 00:12

Allen Zhang


1 Answers

There are three ways to do this:

  1. Put an *ngIf in parent. Only render child when parent's items is ready.
<div *ngIf="items">    <child [items]="items | async"> </div> 
  1. Separate your input getter setter in child. Then act whenever the value is set, you can use RxJS BehaviorSubject also.
private _items = new BehaviorSubject<Items[]>([]);  @Input() set items(value: Items[]) {      this._items.next(value);  }  get items() {    return this._items.getValue(); }  ngOnInit() {     this._items.subscribe(x => {        this.chunk(x);     }) } 
  1. Do it during the ngOnChanges of the child. Refer to here for example. https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#onchanges
like image 188
Chybie Avatar answered Oct 10 '22 09:10

Chybie