如何确保在从类调用函数之前完成构造函数/ ngOnInit?

时间:2017-02-06 19:59:27

标签: angular promise angular-promise angular2-services

我有一个类,在初始化时从服务中检索数据并填充其中一个属性,即一个数组。这个类有一个函数可以对这个数组进行排序,过滤和返回。 当我实例化这个类的对象并调用这个函数时,我意识到它在构造函数和ngOnInit()函数完成之前被调用(可能是因为我使用来自Observables的异步内容,服务返回)。在外部调用我的类的任何函数之前,如何保证构造函数和init已完全执行?

    export class BaseChoice implements PickAppraiser, OnInit {
weight = 0;
options = new Array<PickQuality>();

constructor(private championService: ChampionService) {}

ngOnInit() {
    // Iterates through the list of champions adding them to the current object
    this.championService.getChampions()
        .subscribe(champions => {
            // Iterates through the list of champions adding them to the current object
            Object.keys(champions).map(key => this.options.push(new PickQuality(champions[key], 0)))
        })
}

choose(n?: number): PickQuality[] {
    var sorted = this.options.sort((a, b) => a.score - b.score);
    return sorted;
}

}

我也尝试过像

这样的事情
    choose(n?: number): PickQuality[] {
    // Iterates through the list of champions adding them to the current object
    this.championService.getChampions()
        .subscribe(champions => {
            // Iterates through the list of champions adding them to the current object
            Object.keys(champions).map(key => this.options.push(new PickQuality(champions[key], 0)))
            this.reevaluate(this.options);

            var sorted = this.options.sort((a, b) => a.score - b.score);
            var chosen;
            if(n) chosen = sorted.slice(1, n);
            else chosen = sorted.slice(1, 2);
            return chosen;
        });
}

我在choose()方法本身内运行异步请求,但它不允许我这样做,我假设因为返回变量不能保证存在。

3 个答案:

答案 0 :(得分:1)

我认为,你应该看看你是如何从根本上布置你的组件的。您可以利用observables的方式将它们用作角度支持模板中的异步管道。

我不确定您的组件的详细信息,但我会做这样的事情:

export class BaseChoice implements PickAppraiser, OnInit {
    weight = 0;
    options$: Observable<PickQuality>;
    champions$ : Observable<Champion>;

    constructor(private championService: ChampionService) {}

    ngOnInit() {
        this.champions$ = this
            .championService.getChampions();

        this.options$ = this.champions$.map((champion, index) => {
          return new PickQuality(champion, 0)))
      })
    }
}

在您的模板中,如果您执行*ngFor="let option in options$ | async),它会自动运行该流并为您提供结果,然后在您的choose()函数中,我假设这是用户所采取的操作点击一下,你可以直接通过选项来做一些事情。

如果它比这更复杂,您可以将其映射到点击流,例如championClicked$,并将这些点击映射到选项流中的正确选项。

要记住的是,您需要使用一系列操作设置这些observable,并且该管道每个Observer(订阅者)运行一次,这意味着每次使用| async管道它订阅并运行整个事情。

花一些时间了解RxJS将为你的Angular 2开发带来巨大回报。

答案 1 :(得分:0)

由于您正在将options属性初始化为空数组options = new Array<PickQuality>();,为什么不检查choose方法呢?

choose(n?: number): PickQuality[] {
    if (this.options && this.options.length !== 0) {
       var sorted = this.options.sort((a, b) => a.score - b.score);
       return sorted;
    } else {
       /* do something else if options is empty */
    }
}

---编辑---

这是我在评论中提到的粗略版本:

export class BaseChoice implements PickAppraiser, OnInit {
weight = 0;
options = new Subject<PickQuality[]>();

constructor(private championService: ChampionService) {}

ngOnInit() {
    this.championService.getChampions()
        .subscribe(champions => {
            Let arr = [];
            Object.keys(champions).map(key => arr.push(new PickQuality(champions[key], 0)));
             this.options.next(arr);
        })
}

choose(n?: number): PickQuality[] {
    return this.options.take(1).sort((a, b) => a.score - b.score);
}
}

答案 2 :(得分:0)

如果您从模板中调用choose(n),则可以添加* ngIf =&#34;选项&#34;到模板中的标签。你必须改变你宣布的方式&#34;选项&#34;所以在加载数据之前它是未定义的。像这样:

options: PickQuality[];

如果您从服务中调用choose(n),我会将其更改为返回Observable或Promise。