ค้นหาเว็บไซต์

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);
      });
   }
}

หวังว่ามันจะช่วยหรื่อให้แนวคิดใหม่ๆ กับคุณได้