我是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
});
}
}
知道如何访问/检索组件中的数据?
答案 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>
欢呼声