【问题标题】:Angular 2 how to make child component wait for async data to be readyAngular 2如何让子组件等待异步数据准备好
【发布时间】:2017-05-14 08:02:20
【问题描述】:

我正在将异步数据从父组件传递到子组件。并且子组件需要知道数据的长度才能做某事。

问题是子组件无法使用“Oninit”挂钩来完成工作,因为此时数据不可用。那我该怎么做呢?

父组件代码如下:

@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
            );
    }

}

子组件看起来像:

@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;
    }
}

处理此问题的最佳做法是什么?

【问题讨论】:

    标签: angular


    【解决方案1】:

    有三种方法可以做到这一点:

    1. *ngIf 放在父级中。仅当父母的items 准备好时才渲染孩子。
    <div *ngIf="items">
       <child [items]="items | async">
    </div>
    
    1. 将您的输入 getter setter 分开。然后在设置值时执行操作,您也可以使用 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);
        })
    }
    
    1. 在孩子的ngOnChanges 期间进行。例如,请参阅此处。 https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#onchanges

    【讨论】:

    • 最终选择选项 2。行为完全符合预期。非常感谢。
    • @Milad,对不起?我不明白你。
    • @Milad,如果您足够仔细地检查已回答的日期时间,您会发现 Chybie 的回答比您早。因此,我将他的回答标记为已接受。
    • value setter 就足够了,但我喜欢 Observable 的味道 :)
    • 感谢您的回答!看到它后它是“明显的”,但它在今天的一部分时间里一直躲在我面前。
    【解决方案2】:

    你可以使用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;
        }
    }
    



    顺便说一句,我觉得你的父组件也不对,应该是:

    @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
         }    
    
    }
    

    【讨论】:

    • 感谢您的回答。但是 itemService 目前不返回可观察的。将来可能会。
    【解决方案3】:

    更简单的解决方案:

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

    【讨论】:

    • 值得一提的是,ngOnChanges会在ngOnInit之前运行。
    猜你喜欢
    • 2018-08-12
    • 1970-01-01
    • 2021-04-26
    • 1970-01-01
    • 2020-08-26
    • 2020-08-07
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多