typescript - Angular ไม่อัปเดตมุมมองด้วยตัวแปร boolean ใน pipe ของ rxjs
ฉันมีปัญหากับ Angular 14 ซึ่งไม่อัปเดตมุมมองเมื่อเรียกดูข้อมูล
ฉันต้องการแสดงสัญลักษณ์การโหลด (loading spinner) ใน HTML ของฉันเมื่อข้อมูลกำลังถูกโหลดจากเซิร์ฟเวอร์ ฉันกำลังใช้ ngbTypeahead สำหรับคำแนะนำ/คำใบ้ เมื่อฉันตั้งค่าตัวแปร boolean ในฟังก์ชัน มันไม่แสดงอะไรในมุมมอง ฉันพยายามใช้ NgZone และวิธี run สำหรับบังคับให้ Angular อัปเดตมุมมอง แต่ดูเหมือนว่าจะไม่ได้ผลสำหรับฉัน
นี่คือ TS
public isLoadingVisible: boolean = false
public suggestStations: OperatorFunction<string, Array<Station>> = (text$: Observable<string>) => {
this.zone.run(() => this.isLoadingVisible = true)
const suggestion = text$.pipe(
debounceTime(200),
distinctUntilChanged(),
switchMap((searchText: string) => this.dataService.suggestStations(searchText.toLowerCase())),
);
this.zone.run(() => this.isLoadingVisible = false)
return suggestion
}
// Also tried to put loading into the switchMap function, nut not working as well
public suggestStations: OperatorFunction<string, Array<Station>> = (text$: Observable<string>) => {
return text$.pipe(
debounceTime(200),
distinctUntilChanged(),
switchMap((searchText: string) => {
this.zone.run(() => this.isLoadingVisible = true)
const result = this.dataService.suggestStations(searchText.toLowerCase())
this.zone.run(() => this.isLoadingVisible = false)
return result
}),
);
}
มุมมอง HTML
<p *ngIf="isLoadingVisible">Loading...</p>
<div class="input-group mb-4">
<input [(ngModel)]="selectedStation"
[editable]='false'
[inputFormatter]="formatter"
[ngbTypeahead]="suggestStations"
[resultFormatter]="formatter"
[resultTemplate]="station_row"
class="form-control p-2"
placeholder="Název stanice"
type="text">
</div>
คุณพอจะทราบไหมว่า ปัญหาอาจจะอยู่ที่ไหน? ขอบคุณมากสำหรับความช่วยเหลือของคุณ!
คำตอบ #1
ดูเหมือนว่า ngbTypeahead จะสมัครสมาชิกกับ suggestStations ภายใน ตัวที่คุณมีทั้งสองกรณีไม่ถูกต้องเพราะคุณไม่ได้รอให้ Observable ภายในเสร็จสิ้นหรือคุณเปลี่ยน isLoadingVisible นอกสายโซ่
ดังนั้นสิ่งที่คุณควรทำคือใส่ isLoadingVisible เข้าสู่สายโซ่และตรวจสอบให้แน่ใจว่าคุณกระตุ้นการตรวจสอบการเปลี่ยนแปลงด้วยตัวเอง
constructor(
private cdr: ChangeDetectorRef,
) {}
...
public suggestStations: OperatorFunction<string, Array<Station>> = (text$: Observable<string>) => {
return text$.pipe(
tap(() => {
this.isLoadingVisible = true;
this.cdr.markForCheck();
}),
debounceTime(200),
distinctUntilChanged(),
switchMap((searchText: string) => this.dataService.suggestStations(searchText.toLowerCase())),
tap(() => {
this.isLoadingVisible = false;
this.cdr.markForCheck();
}),
);
}
คำตอบ #2
ฉันใช้บางอย่างแบบนี้
pipe(tap(() => this.loading.showLoading()),
finalize(() => this.loading.hideLoading())
ที่ซึ่งมีการโหลดและคลาสที่ถูกฉีดเพื่อจัดการตัวแปรนี้ทั่วทั้งระบบ ฉันได้ดำเนินการนอกโซนเพื่อไม่ให้เกิดการรีเฟรชโดยอัตโนมัติและใช้ setTimeout ด้วยเวลาศูนย์เพื่อให้รีเฟรชมุมมองหนึ่งครั้ง (อาจไม่ใช่โค้ดที่สะอาดมาก แต่ทำงานได้)
@Injectable({ providedIn: 'root' })
export class Loading{
showLoading(): void {
this.zone.runOutsideAngular(() => {
setTimeout(() => {
this._isLoading$.next(true);
}, 0);
});
}
}
หวังว่ามันจะช่วยหรื่อให้แนวคิดใหม่ๆ กับคุณได้
