Как показать данные предыдущего наблюдаемого до тех пор, пока новый наблюдаемый не выдаст значение - PullRequest
1 голос
/ 27 мая 2020

В моем html я использую asyn c pipe для подписки на наблюдаемое, как показано ниже.

<button  (click)="getData(1)" >getUser1</button>
<button style="margin:50px;" (click)="getData(2)" >getUser2</button>
<div>------------------------------------------</div>
<div *ngIf="userData$ |async as user">
data is{{  user | json}}</div>

и этот наблюдаемый userData $ становится новым каждый раз, когда пользователь нажимает на button1 или 2.

  getData(id) {

   this.userData$ = this.getDataFromBackend(id);
  }

 getDataFromBackend(id) {
    //delay added to simulate network delay
    // fake backend call but i have to use real one in actual project
  return of(this.dataSource[id]).pipe(delay(1000));
  }

теперь всякий раз, когда пользователь переключается с user1 на user2, назначается новая наблюдаемая. и так как этой новой наблюдаемой требуется некоторое время, чтобы получить данные, на этот раз она отображается пустой.

можем ли мы сделать что-то, чтобы до тех пор, пока новые наблюдаемые данные не вернутся, мы могли бы показать предыдущие данные.

  I can not user loader here meanwhile.
  I know i can do something like 
  let subject = new Subject();
  let userObservable$ = subject.asObservable()
  and use this observable in the html
  and the subscribe to these observable form getDataFromBackend() here in the class and from 
  subscription do the subject.next() and it will send the updated value
  but this does not seem the best way as it do the manual subscription in the component

ниже ссылка на stackblitz, показывающая проблему.

https://stackblitz.com/edit/angular-ivy-d9nsxu?file=src%2Fapp%2Fapp.component.ts

Ответы [ 4 ]

1 голос
/ 29 мая 2020

Я бы использовал один из двух вариантов:

Вариант 1

Вы создаете другой Observable (loading$ или state$) в вашем DataSource (Service , Я полагаю?), Который обеспечивает либо логическое указание, загружается он или нет, либо (что еще лучше) «состояние» (перечисление), способное указать, находится ли он «в исходном состоянии», «загружен», «загружается» и т. Д. c.

Вариант 2

Вы можете изменить содержимое, которое проходит через userData$ Observable. Я бы предположил, что Observable будет посредником в следующей структуре данных:

{
  user: { ... }, // Containing the user data that has been loaded
  state: "Loaded",
}

(при загрузке пользовательских данных) и:

{
  user: { ... }, // Containing the previously loaded user's data
  state: "Loading",
}

(при загрузке пользовательских данных)

Ну, честно говоря, я бы, скорее всего, использовал систему управления состоянием, похожую на redux, такую ​​как:

Но это уже другая история

1 голос
/ 27 мая 2020

Вот способ сделать это без подписки вручную:

app.component.ts

export class AppComponent  {

  userData$ :Observable<any>;
  dataSource = {1:{user:'user1', id:1}, 2: {user:'user2', id:2}};

  private userSrc = new Subject<number>();

  ngOnInit () {
    this.userData$ = this.userSrc.pipe(
      startWith(1),
      switchMap(id => this.getDataFromBackend(id)),
    )
  }

  getData(id) {
    this.userSrc.next(id);
  }

  getDataFromBackend(id) {
    return of(this.dataSource[id]).pipe(delay(1000));
  }
}

StackBlitz .

0 голосов
/ 27 мая 2020

Причина исчезновения данных заключается в том, что вы мгновенно перезаписываете объект userData$ новым наблюдаемым, который еще не вернул результат.

Возможно, вы можете подписаться на вызов getDataFromBackend и перезаписать userData $ при возврате результата:

  userData$ = new Subject();
  dataSource = {1:{user:'user1', id:1}, 2: {user:'user2', id:2}};

  getData(id) {
    this.getDataFromBackend(id).subscribe(res => this.userData$.next(res));
  }
0 голосов
/ 27 мая 2020

Вы можете добавить блок else к блоку *ngIf. Попробуйте следующее

<div *ngIf="userData$ |async as user; else elseBlock">
  data is {{ user | json }}
</div>
<ng-template #elseBlock>
  Loading...
</ng-template>

Я изменил ваш Stackblitz

...