在Angular 5中等待渲染视图之前的数据

时间:2018-03-27 04:15:35

标签: angular typescript

我是Angular 5的新手,能够创建使用订阅访问服务方法的视图,但在渲染中遇到延迟问题。用户看到第一个“未定义”字符串,0.5秒后它会更改为正确的值。

以下是组件的.ts文件:

 public trips: Trip[];
  public numberOfUsers : Map<string, number> = new Map<string, number>();

  constructor(private tripService: TripService) { }

  ngOnInit() {
   this.getTrips();
  }

  getTrips() {
    this.tripService.getTripForMe().subscribe(
      data => { this.trips = data;},
      err => console.error(err),
      () => this.initNumberOfUsers()
    );
  }

  initNumberOfUsers() {
    for (let i = 0; i < this.trips.length; i++) {
      let count;
      this.tripService.getNumberOfUsers().subscribe(
        data => { count = data},
        err => console.error(err),
        () => this.numberOfUsers.set(this.trips[i].id, count)
      );


      ;
    }
  }

  getNumberOfUsers(data) {
    return this.numberOfUsers.get(data.id);
  }

方法initNumberOfUsers在第一次订阅完成后调用,这是好的,但getNumberOfUsers(数据)可能在之前调用并获得“未定义”。

以下是模板的相关部分(“data”是ngFor循环的当前值):

<span [innerText]="getNumberOfUsers(data)"></span>

有没有办法确保两个订阅方法在呈现之前按顺序完成?

更新

我能够创建一个解析器,而concole显示该对象但是,我很难将数据传递给组件。

解析器代码:

import { Injectable } from '@angular/core';
import { Router, Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Trip} from ....
import { TripService } from .....
import { Observable } from 'rxjs/Rx';

@Injectable()
export class TripsResolve implements Resolve<Trip[]> {

   public trips: Trip[];

   constructor(private service: TripService) {}

   resolve(route: ActivatedRouteSnapshot, 
           state: RouterStateSnapshot) {
     this.service.getTrips().subscribe(
        data => { this.trips = data },
        err => console.error(err),
        () => console.log(this.trips)
      );
      return this.trips;
   }
}

来自路线

resolve: {
         trips: TripsResolve
      }

来自模块

providers: [
        ...
        TripsResolve,
        ...

组件中的数据未通过/不可用:

import { Component, OnInit } from '@angular/core';
import { Trip } from ...
import { Router, ActivatedRoute } from '@angular/router';

@Component({
  selector: ...
  templateUrl: ...
  styleUrls: ...
})
export class MyComponent implements OnInit {

    public trips: Trip[];

    constructor(private route: ActivatedRoute,
                private router: Router) {
    }

    ngOnInit() {
        this.route.data.forEach(data => {
            this.trips = data.trips;
            console.log(this.trips);  //can't see it
       });

    } 
}

知道如何访问/检索组件中的数据?

3 个答案:

答案 0 :(得分:10)

当我通过API调用处理数据时,我遇到了类似的问题

我尝试了两种解决方案

一个是使用 * ngIf

只有在数据准备好后才会填充DOM。

<div *ngIf="isLoaded">Text to show</div>

另一个是使用解析器,在渲染视图本身之前,它将准备数据。但是,如果数据加载花费太多时间,有时解析器会将屏幕保持为空白。

@Injectable()
export class HeroDetailResolve implements Resolve {
    constructor(private heroService: HeroService, private router: Router) { }

    resolve(route: ActivatedRouteSnapshot): Promise | boolean {
        let id = +route.params['id'];
        return this.heroService.getHero(id).then(hero => {
            if (hero) {
                return hero;
            } else { // id not found
                this.router.navigate(['/dashboard']);
                return false;
            }
        });
    }
}

所以你现在有两个选择。

我建议 * ngIf。在加载数据时,显示一些加载程序gif或一些消息,让用户知道后台发生的事情。

答案 1 :(得分:1)

检查Angular中的解析器。

这是一个链接: https://angular.io/api/router/Resolve

就像守卫一样,它们在组件完全创建之前运行,并且阻止您在加载时等待模板中的if / else逻辑。

如果您不想使用解析器,您还可以执行以下操作:

data(iris)

iris2 <- cbind(iris,rep('a',nrow(iris)))
names(iris2)[6] <- 'CORE'

out <- myApp(iris2[,5:6],iris2[,1:4])
在呈现<span *ngIf="myVariable; else stillLoading" [innerText]="getNumberOfUsers(data)"></span> <ng-template #stillLoading><p>Loading...</p></ng-template> 标记之前,

myVariable将是您想要定义的任何内容。我只是不想仔细查看你的地图:)

是否在模板中使用解析器或if / else的选择取决于您希望用户体验的样子。可能还有其他原因,但首先想到的是。

答案 2 :(得分:1)

您可以使用mergeMap组合这两个订阅。这样,一旦触发了最后一个子方法,它们就会发出。

虽然在您的情况下,您可能会发现将numberOfUsers初始化为null更容易。然后在您的模板中使用ng-show仅在numberOfUsers不为空时显示范围。

前:

<div *ngShow="numberOfUsers">
  <span [innerText]="getNumberOfUsers(data)"></span>
</div>

欢呼声

相关问题