Angular & Firestore: получить асинхронный доступ к базе данных - PullRequest
0 голосов
/ 12 ноября 2018

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

Итак, у меня есть угловое приложение, и я использую Firestore в качестве базы данных. Поэтому я использую этот фрагмент кода, чтобы получить мою коллекцию в сервисе:

this.userAsteroid$ = this.afs.collection<UserAsteroid>(this.collection).valueChanges();

У меня есть функция в serivce, которая возвращает this.userAsteroid $. Затем в моем компоненте, в моем ngOnInit, у меня есть это:

this.userAsteroid$ = this.userAsteroidService.getAsteroids();

this.userAsteroid$.subscribe(asteroids => {
  asteroids.forEach(document => {
    if (document.asteroidId == this.id && document.userId == this.user.uid) {
      this.hasAsteroid = true;
      console.log("test: ", this.hasAsteroid);
    }
    console.log(document);
  });
});

Таким образом, по сути, мой компонент - это страница сведений для определенного астероида, и когда в моей коллекции есть документ, который содержит идентификатор астероида и идентификатор пользователя, который вошел в систему, я хочу, чтобы мой bool hasAsteroid был установлен в true .

Это HTML-код для компонента:

    <div [hidden]="loading">
  <div class="columns" *ngIf="!hasAsteroid && user">
    <div class="column">
        <button class="button is-primary is-outlined" type="button" (click)="addAsteroid(id)">Add to my asteroids</button>
    </div>
  </div>

Теперь это работает, но только когда я перезагружаю страницу, а не когда я к ней перехожу. Я подозреваю, что это как-то связано с тем фактом, что функция подписки, которую я использую, не является асинхронной, и поэтому иногда моя страница загружается до того, как bool был установлен в true, а затем мой * ngIf, использующий bool, не работа.

Я пытался использовать .pipe и затем отображать, как я делал бы с данными JSON, которые я получаю от API, но в этом случае это ничего не делает.

В другом компоненте я использую ту же функцию из сервиса, чтобы на этот раз получить все астероиды, сохраненные одним пользователем, например:

getUserFeed() {
this.authService.userData$.subscribe(data => this.user = data);
this.userAsteroid$ = this.userAsteroidService.getAsteroids();

this.userAsteroid$.subscribe(asteroids => {
  asteroids.forEach(document => {
    if (document.userId == this.user.uid) {
      console.log(document.asteroidId);
      this.dataArray.push(document.asteroidId);
    }
  });
})}

Как вы можете видеть, я помещаю все идентификаторы астероидов, которые пользователь сохранил в массив, поэтому позже я могу использовать их для вызова API.

Я не стал писать здесь остальную часть кода, потому что я знаю, что он не будет работать из-за не асинхронной функции.

Если у кого-то есть решение, или он может указать мне нужную документацию, которая мне нужна для этого, я был бы чрезвычайно благодарен.

EDIT:

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

this.authService.userData$.subscribe(data => {
  this.user = data;

  this.userAsteroid$ = this.userAsteroidService.getAsteroids();

  this.userAsteroid$.subscribe(asteroids => {
    asteroids.forEach(document => {
      if (document.asteroidId == this.id && document.userId == this.user.uid) {
        this.hasAsteroid = true;
        console.log("test: ", this.hasAsteroid);
      }
      console.log(document);
    });
  });
});

По сути, я подписываюсь на свой authSerivce, чтобы определить моего пользователя, в этой подписке я подписываюсь на мой сервис Firestore, а затем делаю кое-что.

Это все работает, когда я первоначально загружаю свой компонент. Однако я использую параметры в своих маршрутах для сортировки при работе с «вкладками». Я подписываюсь на эти параметры в моем ngOnit, чтобы при нажатии на ссылку в моей навигации моя страница обновляла компонент с правильным параметром. В этой подписке я вспоминаю свою функцию.

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

this.userAsteroid$.subscribe(asteroids => {

У кого-нибудь есть идеи, почему?

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

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

В противном случае это зависит от порядка, в котором вы получите ответ: если вы получите астероиды до , тогда this.user еще не установлено.

Вы можете видеть это с console.log в каждом обработчике событий, и это должно быть очевидно.

Таким образом, ваш код станет:

getUserFeed() {
this.authService.userData$.subscribe(data => {
  this.user = data;
  this.userAsteroid$ = this.userAsteroidService.getAsteroids();

  this.userAsteroid$.subscribe(asteroids => {
    asteroids.forEach(document => {
      if (document.userId == this.user.uid) {
        console.log(document.asteroidId);
        this.dataArray.push(document.asteroidId);
      }
    });
  });});
}
0 голосов
/ 12 ноября 2018

Как насчет перемещения поиска документов в подписку auth?

getUserFeed() {
  this.authService.userData$.subscribe(data => {
    this.user = data
    this.userAsteroid$.subscribe(asteroids => {
      asteroids.forEach(document => {
        if (document.userId == this.user.uid) {
          console.log(document.asteroidId);
          this.dataArray.push(document.asteroidId);
        }
      });
    })}
  });
  this.userAsteroid$ = this.userAsteroidService.getAsteroids();
}

Таким образом, вы гарантируете, что подписка userAsteroid$ будет настроена только после того, как станет доступна this.user.

Если вы пойдете по этому пути, вы, вероятно, захотите определить, подписались ли вы уже на this.userAsteriud$ и пропустить повторную подписку в этом случае.

...