typescript - รอข้อมูลก่อนการเรนเดอร์มุมมองใน Angular 5
ฉันเป็นมือใหม่ใน Angular 5 และสามารถสร้างวิวที่เข้าถึงเมธอดของเซอร์วิสได้โดยใช้ subscribe แต่พบปัญหาเรื่องความล่าช้าในการเรนเดอร์ ผู้ใช้จะเห็นสตริง "undefined" ก่อน และหลังจาก 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) น่าจะถูกเรียกก่อนและได้ค่า "undefined"
นี่คือส่วนที่เกี่ยวข้องจากเทมเพลต ("data" คือค่าปัจจุบันของลูป ngFor)
<span [innerText]="getNumberOfUsers(data)"></span>
มีวิธีใดที่จะทำให้แน่ใจว่าทั้งสองวิธีการสมัครจะเสร็จสิ้นตามลำดับก่อนการแสดงผลหรือไม่?
อัปเดต
ฉันสามารถสร้างตัวแก้ปัญหาได้และคอนโซลแสดงวัตถุ แต่ฉันมีปัญหาในการส่งข้อมูลไปยังคอมโพเนนต์
รหัสรีโวลเวอร์:
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
});
}
}
มีไอเดียไหมว่าฉันจะเข้าถึง/ดึงข้อมูลในคอมโพเนนต์ได้อย่างไร?
คำตอบ #1
ฉันเคยเจอปัญหาแบบเดียวกันเมื่อฉันจัดการกับข้อมูลผ่านการเรียก API
ฉันได้ลองใช้สองวิธีแก้ปัญหา
มีการใช้ *ngIf
DOM จะถูกเติมเต็มก็ต่อเมื่อข้อมูลพร้อมแล้ว
<div *ngIf="isLoaded">Text to show</div>
อีกหนึ่งวิธีคือการใช้ resolver ซึ่งก่อนที่จะแสดงมุมมองจริง ๆ มันจะเตรียมข้อมูลก่อน แต่บางครั้ง resolver จะทำให้หน้าจอของคุณว่างเปล่า หากการโหลดข้อมูลใช้เวลานานเกินไป
@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 โหลดหรือข้อความบางอย่างเพื่อให้ผู้ใช้ทราบว่ามีบางอย่างเกิดขึ้นเบื้องหลัง
คำตอบ #2
ตรวจสอบ resolvers ใน Angular
นี่คือลิงก์: https://angular.io/api/router/Resolve
คล้ายกับผู้รักษา พวกมันทำงานก่อนที่คอมโพเนนต์จะถูกสร้างขึ้นอย่างสมบูรณ์ และป้องกันไม่ให้คุณต้องมีตรรกะ if/else ในเทมเพลตของคุณสำหรับการรอขณะโหลด
ถ้าคุณไม่ต้องการใช้ตัวแก้ปัญหา คุณก็สามารถทำบางอย่างเช่น:
<span *ngIf="myVariable; else stillLoading" [innerText]="getNumberOfUsers(data)"></span>
<ng-template #stillLoading><p>Loading...</p></ng-template>
myVariable จะเป็นอะไรก็ตามที่คุณต้องการกำหนดก่อนที่คุณจะแสดงแท็ก <span> ฉันแค่ไม่อยากมองลึกลงไปในแผนที่ของคุณ :)
การเลือกว่าจะใช้ตัวแก้ไขปัญหาหรือ if/else ในเทมเพลตก็ขึ้นอยู่กับว่าคุณต้องการให้ประสบการณ์ผู้ใช้ของคุณเป็นอย่างไร อาจจะมีเหตุผลอื่นๆ ด้วย แต่เหตุผลนี้น่าจะเป็นสิ่งแรกที่นึกออก
