Обновление части наблюдаемой, используемой в asyn c pipe - PullRequest
2 голосов
/ 07 марта 2020

У нас есть страница, где есть несколько разделов. Каждый раздел может иметь карточку или стол. Наблюдаемый связывает данные в html, используя asyn c pipe. Теперь мне нужно обновить одну таблицу без обновления всей наблюдаемой.

  loadPageData(Id): void {
    this.sections$ = this.psService.getLoadPageData(Id).pipe(
      switchMap(sections => forkJoin(
        sections.map(section => this.psService.getSectionData(section.sectionID).pipe(
          map(card => Object.assign({}, section, { card })),
          switchMap(c => c.card.map(card => iif(() => card.cardTypeId === 3,
            from(this.psService.getTable(this.tablePerodID).pipe(map(table => Object.assign({}, c, { table })))),
            of(c))))
        ).concatAll()
        ))
      ));
  }

  updateTable(sectionId, tablePerodID) {
    let tableData;
    this.psService.getTable(tablePerodID).subscribe((data) => {
      tableData = data;
    });
    this.sections$.forEach(sections => {
      sections.forEach(section => {
      if (section.sectionID === sectionId) {
        section.table = sectionData;
      }
    });
    });
  }

и HTML выглядит следующим образом:

<div *ngFor="let section of sections$ | async;">
  <div *ngFor="let card of section.card | sort:'displayOrder';">
    <app-card></app-card>
    <div *ngIf="card.cardTypeName === 'Table'">
      <app-table></app-table>
    </div>
   </div>
 </div>

Теперь возникает проблема, когда я пытаюсь загрузить данные для таблицы с помощью updateTable [когда пользователь меняет tablePerodID], это делает ничего. Я пытался .next(), но он обновляет весь section$. В любом случае я могу только обновить таблицу?

Ответы [ 2 ]

3 голосов
/ 17 марта 2020

Это похоже на недопонимание того, как работают трубы.

Сравни

Подумайте о водопроводах.

Представьте, что вам нужен кран, чтобы налить сахарную воду.

Если вы возьмете стакан воды из-под крана и добавите в него сахар, вы больше не сможете снова заливать эту воду в кран.

Решением будет добавление куска трубы с система добавления сахара до того, как вы выпьете стакан воды.

rx js трубы такие же, как только вы подпишетесь, пути назад уже не будет. (если вы не создадите новую трубу и не нальете в нее воду;)

Решение состоит в том, чтобы все пускать по трубам. Только subscribe, когда вы хотите получить значение. Это также повышает производительность.

Решение

this._cache$: BehaviorSubject<Section[]> = new BehaviorSubject<Section[]> ([]);
this.sections$: Observable<Section[]>;
loadPageData(id: number): void {
    // subcribe once and save the values in the cache
    this.fetchPageData(Id).subscribe(data => this._cache$.next(data));

    // section$ will emit values when caché changes
    this.sections$ = this._cache$.asObservable();
}

fetchPageData(Id): Observable<Section[]> {
    // call your data service
    return this.psService.getLoadPageData(Id).pipe(
       //...
    );
}

updateTable(sectionId, tablePerodID) {
    let tableData;
    this.psService.getTable(tablePerodID).subscribe((data) => {
      tableData = data;
    });

    this.sections$ = this.sections$.pipe(
        map(sections => sections.map(section =>
        {
            if (section.sectionID === sectionId) {
                section.table = tableData;
             }
        })
    );
}

Вместо подписки на наблюдаемое направьте операцию обновления.

updateTable обновит sections$ наблюдаемый и html асинхронный c канал обновит результаты.

Использование _cache$ имеет другое улучшение производительности, поскольку каждый раз, когда вы обновляете канал, он не будет вызывать вашу службу данных. (Не обязательно использовать его)

Уточнение: это обновит ваш канал в вашем приложении, а не данные в базе данных или где-либо еще.

0 голосов
/ 01 апреля 2020

Спасибо @adrisons за предоставленную мне идею кеширования. Вот решение, которое сработало для меня. Он немного отличается от ответа @adrisons тем, что не использует наблюдаемый.

  _cached: any; 
  sections$: Observable<any>;

  loadPageData(Id): void {
    // Load data from server
    this.sections$ = this.psService.getLoadPageData(Id).pipe(
      switchMap(sections => forkJoin(
        sections.map(section => this.psService.getSectionData(section.sectionID).pipe(
          map(card => Object.assign({}, section, { card })),
          switchMap(c => c.card.map(card => iif(() => card.cardTypeId === 3,
            from(this.psService.getTable(this.tablePerodID)
            .pipe(map(table => Object.assign({}, c, { table })))),
            of(c))))
        ).concatAll()
        ))
      ), first(), // Tap and get the first emit and assign to cache
      tap((data: any) => {
        this._cached = data // Caching the data without subscribing.
      }));
  }

  updateTable(sectionId, tablePerodID) {
    // Get table Data from backend and update cache
    this.psService.getTable(tablePerodID).subscribe((data) => {
      this._cached.map(section => {
        if (section.sectionID === sectionId) {
          section.table = data;
        }
      });
    });
    // Refresh async observable from cache
    this.refreshFromCache();
  }

  refreshFromCache() {
    this.sections$ = of(this._cached)
  }
...