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

I pass async data from the parent component to the child component. And the child component must know the length of the data in order to do something.

How the problem is that the child component cannot use the Oninit hook to do the work, because the data is currently unavailable. So how do I do this?

The code of the parent component looks like this:

@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 is as follows:

 @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 for this?

+17
angular
source share
3 answers

There are three ways to do this:

  1. Put *ngIf in the parent. Display child items only when parent items are ready.

     <div *ngIf="items"> <child [items]="items | async"> </div> 
  2. Divide your input setter getter by child. Then act whenever the value is set, you can also use RxJS BehaviorSubject .

     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); }) } 
  3. Do this during the ngOnChanges child. Contact here, for example. https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#onchanges

+31
source share

You can use the setter:

 export class child implements OnInit{ itemChunks: Items[][]; private _items ; //bellow will get called when ever the items are passed in by the parent component @Input( 'items' ) set items ( items: Items[] ) { this._items = items; 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; } } 



By the way, I feel that your parent component is also wrong, it should be:

 @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 ) { this.items = this.itemService.getItemss(); // if getItemss is returning an observable, which I think it does } } 
+1
source share

A simpler solution:

 ngOnChanges(changes: SimpleChanges) { if (changes['items'].currentValue) { this.items = items } } 
0
source share

All Articles