Проверьте, вернул ли Observable (запрос http) значение и не ожидал ли он этого? - PullRequest
0 голосов
/ 03 февраля 2019

У меня есть календарь внутри приложения Angular (calendarComponent), который получает свои записи через облачные функции Firebase из mongodb (через службу под названием calendarService).Чтобы создать новую запись, я выскакиваю диалог углового материала (addEventComponent).Для этого диалога нужны данные из базы данных.До сих пор компонент диалога запрашивает данные из calendarService, который выполняет новый http-запрос каждый раз, когда я хочу добавить запись.Помимо заметной задержки, это может привести к увеличению затрат в зависимости от тарифного плана пожарной базы.В идеале calendarComponent будет запрашивать данные из calendarService в ngOnInit и передавать их в addEventComponent по запросу, но это работает только в том случае, если запрос http завершается при нажатии нового диалогового окна ввода.Я слишком неопытен с angular и rxjs, чтобы решить эту проблему не безобразным образом.

То, что я изначально пробовал, было примерно таким:

Внутри calendarComponent

requiredData: RequiredData[];

ngOnInit() {
  this.calendarService.getRequiredData().subscribe(response => {
    this.requiredData = response.data;
  });
}

addNewEntry () {

  const dialogData = this.requiredData;

  const dialogRef = this.dialogModal.open(AddEventComponent, {
    data: { requiredData: dialogData },
  });

}

(CalendarService просто возвращает запрос http.get (), поэтому я не написал здесь код.)

Пока запрос http не выполняется вечно, он прекрасно работает.В качестве временного решения я запустил http-запрос, как и раньше, но сохранил ответ в calenderService и возвратил наблюдаемое из этого.Это выглядит так:

Внутри calendarComponent

ngOnInit() {
  this.calendarService.getRequiredData();
}

Внутри calendarService

private requiredData$ = new Subject<RequiredData>();
requiredData: RequiredData[];

getRequiredData () {
  this.http.get<{ _msg: string, reqData: RequiredData[] }>(API_URL)
    .subscribe(response => {
      this.requiredData = response.reqData;
      this.requiredData$.next([...this.requiredData]);
    });
}

getReqData () {
  return this.requiredData$.asObservable();
}

Возникла моя проблемавнутри AddEventComponent

requiredData: RequiredData[];

ngOnInit() {
  this.calendarService.getReqData().subscribe(response => {
    this.useTheRequiredData(response);
  });
}

Приведенный выше код не будет работать, поскольку подписка не сработает, если запрос уже завершен.Так что мне нужен более разумный способ сделать это или код, который проверяет, наблюдаемые ли уже испущенные значения, а если нет, ждет первого испуска, а затем запускает последующие функции.Вроде как следующее, но менее грубое и работающее.

внутри AddEventComponent

requiredData: RequiredData[];

ngOnInit() {

  if (this.calendarService.requiredData) {
    this.useTheRequiredData(this.calendarService.requiredData);
  } else {
    this.calendarService.getReqData().subscribe(response => {
      this.useTheRequiredData(response);
    });
  }
}

Любая помощь приветствуется.

Что, кажется, работаетis ( AddEventComponent )

this.calendarService.requiredData
  ? this.useTheRequiredData(this.calendarService.requiredData)
  : this.calendarService.getReqData().pipe(
    take(1),
    tap(response => {
      this.useTheRequiredData(response);
    })
  ).subscribe();

Меня больше всего смутило использование чистой трубы (трубы с угловым фильтром внутри шаблона, а не трубы rxjs), которая не понимала, что это довольно долго.

1 Ответ

0 голосов
/ 04 февраля 2019

Рассматривали ли вы использовать RxJS ReplaySubject вместо обычного Subject?ReplaySubject будет выдавать последнее значение подписчикам при подписке:

https://medium.com/@luukgruijs/understanding-rxjs-behaviorsubject-replaysubject-and-asyncsubject-8cc061f1cfc0

Вместо функции получения, вы можете также выставить свой ReplaySubject как свойство только для чтения иинициализируйте его в своем конструкторе CalendarService:

private requiredDataObservable$: Observable<RequiredData[]>;

[...]

constructor(...) {
  this.requiredDataObservable$ = this.requiredData$.asObservable();
}

Лично я использую суффикс $ для моих открытых наблюдаемых и соответствующее имя без него для субъекта, но это всего лишь соглашениеЯ подобрал:

  /** data subject to propagate changes */
  private data: ReplaySubject<T[]>;

  /** data observable exposed for subscribers */
  protected data$: Observable<T[]>;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...