首页 > 解决方案 > Observable 订阅触发后 Angular UI 未更新

问题描述

我有一个角度页面,它使用服务中的可观察参数。但是,当这个 observable 更新时,页面不会更新以匹配。

我尝试将 observable 的结果存储在一个平面值中,或者更改一个布尔值来调整 UI,但似乎没有任何效果。

记录 observable 确认它确实更新正确,并且在重新导航到页面时显示新值。

其他条件 UI 更新正确地修改了页面,只有以下 ( *ngIf="(entries$ | async), else loading") 中的一个导致了此问题。

组件.ts

export class EncyclopediaHomeComponent implements OnInit {
  entries$: Observable<EncyclopediaEntry[]>;
  categories$: Observable<string[]>;
  entry$: Observable<EncyclopediaEntry>;
  entry: EncyclopediaEntry;
  isEditing: boolean;

  constructor(private route: ActivatedRoute, private encyService: EncyclopediaService) {
    this.entries$ = encyService.entries$;
    this.categories$ = encyService.categories$;

    this.entries$.subscribe(es => {
      console.log(es);
    });

    route.url.subscribe(url => this.isEditing = url.some(x => x.path == 'edit'));
    this.entry$ = route.params.pipe(
      switchMap(pars => pars.id ? encyService.getEntry(pars.id) : of(null)),
    );
    this.entry$.subscribe(entry => this.entry = entry);
  }

  ngOnInit(): void {
  }

  updateEntry(entry: EncyclopediaEntry) {
    this.encyService.updateEntry(entry.id, entry);
  }
}

组件.html

<div class="encyclopedia-container">
    <ng-container *ngIf="(entries$ | async), else loading">
        <app-enc-list [entries]="entries$ | async"
            [selectedId]="entry ? entry.id : null"></app-enc-list>

        <ng-container *ngIf="entry">
            <app-enc-info *ngIf="!isEditing, else editTemplate"
                [entry]="entry$ | async"></app-enc-info>

            <ng-template #editTemplate>
                <app-enc-edit [entry]="entry$ | async" [categories]="categories$ | async"
                    (save)="updateEntry($event)"></app-enc-edit>
            </ng-template>
        </ng-container>
    </ng-container>
    <ng-template #loading>
        <mat-progress-bar mode="indeterminate"></mat-progress-bar>
        <br>
        <p>Loading Encyclopedia...</p>
    </ng-template>
</div>

编辑: service.ts

export class EncyclopediaService {
  entriesSubject = new ReplaySubject<EncyclopediaEntry[]>();
  entries$ = this.entriesSubject.asObservable();
  private _entries: EncyclopediaEntry[];

  constructor(private file: FileService) {
    file.readFromFile(this.projectName+'Encyclopedia').subscribe((es: string) => {
      this._entries = JSON.parse(es);
      this.entriesSubject.next(this._entries);
      this.entries$.subscribe(es => this.file.writeToFile(this.projectName+'Encyclopedia', JSON.stringify(es)));
    });
  }
  .
  .
  .
}

标签: javascriptangulartypescriptobservableangular-changedetection

解决方案


该组件似乎没有看到变化。我不知道为什么,因为 |async 会完成这项工作。

但要修复它,您可以使用 ChangeDetector:


constructor(
   private route: ActivatedRoute,  
   private encyService: EncyclopediaService
   private changeDetectorRef: ChangeDetectorRef,
) {
    this.entries$ = encyService.entries$;
    this.categories$ = encyService.categories$;

    this.entries$.subscribe(es => {
      // setTimeout need to run without troubles with ng changes detector
      setTimeout(_=>{this.changeDetectorRef.detectChanges()},0);
      ...
    });

或者您可以像那里描述的那样使用 markforCheck 。


推荐阅读