Firebase Cloud + Angular6: сохранить ответ из базы данных в свойстве класса - PullRequest
0 голосов
/ 22 октября 2018

Мне так тяжело пользоваться облачным хранилищем из firebase с Angular, что я захожу в тупик.

Я пытаюсь сделать что-то простое: извлечь данные из базы данных исохранение его в переменной класса для дальнейшей обработки.

races: Race[]
ngOnInit() {
    this.races = []

    this.userResolver.getUserInfo().then(
      res => {
        this.userInfo = res
        let docRef = this.db.collection('/players/').doc(this.userInfo.uid).ref
        docRef.get().then(function(doc) {
          if (doc.exists) {
              console.log("Document data:", doc.data());
              let res = doc.data().races
              console.log("res:", res);
              res.forEach(item=>{
                console.log("item:", item);
                console.log(item.id);
                let race = new Race(item.id, item.title, item.progress, item.thumbnail)
                console.log(race);
                this.races.push(race)
              })
              console.log(this.races);

          } else {
              console.log("No such document!");
          }
      }).catch(function(error) {
          console.log("Error getting document:", error);
      });
    }

А вот консольный журнал:

Document data: {races: Array(2)}
res: (2) [{…}, {…}]
item: {id: "Whu855ZbOsIM9SoIE6pu", progress: 50, thumbnail: "", title: "Brasil"}
(id) Whu855ZbOsIM9SoIE6pu
Race {id: "Whu855ZbOsIM9SoIE6pu", progress: 50, thumbnail: "", title: "Brasil"}
Error getting document: TypeError: Cannot read property 'races' of undefined
at menu.component.ts:39
at Array.forEach (<anonymous>)
at menu.component.ts:34
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:388)
at Object.onInvoke (core.js:3820)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:387)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:138)
at zone.js:872
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
at Object.onInvokeTask (core.js:3811)

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

Мне удалось получить данные из Firebase, если они прямо из коллекции с этим кодом:

this.db.collection('/cards')
    .valueChanges()
    .subscribe(res => {
        this.cards = res.map(card=> card as Card);

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

Буду признателен за любую помощь.Я перепробовал все, что видел, но на самом деле документ Firebase для Angular довольно плохой.

Пожалуйста, прочитайте мою проблему и не комментируйте что-то вроде collection ('Players'), и это все.Мне нужно выбрать плеер внутри коллекции.

Спасибо

- Исправлено (спасибо Рено Тарнеку):

let docRef = this.db.collection('/players/').doc(this.userInfo.uid).ref;
docRef.get().then(doc => {
            if (doc.exists) {
                let res = doc.data().races
                res.forEach(item=>{
                  this.races.push(item as Race)
                })
            } else {
                console.log("No such document!");
            }
        }).catch(function(error) {
            console.log("Error getting document:", error);
        });

Кроме того, я изменил свой класс Race на интерфейс, чтобы избежать вызова конструктора.

1 Ответ

0 голосов
/ 22 октября 2018

Я вовсе не специалист по angular, но я думаю, что у вас проблема контекста с this внутри функции, переданной в качестве обработчика docRef.get().then().

Используя синтаксис стрелки, вы должныреши это.Выполните следующие действия:

...
docRef.get().then(doc => {
          if (doc.exists) {
              console.log("Document data:", doc.data());
              let res = doc.data().races
              console.log("res:", res);
              res.forEach(item=>{
                console.log("item:", item);
                console.log(item.id);
                let race = new Race(item.id, item.title, item.progress, item.thumbnail)
                console.log(race);
                this.races.push(race)
              })
              console.log(this.races);

          } 
...

См. Этот вопрос и ответ для получения более подробной информации: Функция стрелки по сравнению с объявлением / выражением функции: являются ли они эквивалентными / заменяемыми?

Выможет также решить это следующим образом:

races: Race[]
ngOnInit() {
    const self = this;
    self.races = []

    self.userResolver.getUserInfo().then(
      res => {
        self.userInfo = res;
        let docRef = self.db.collection('/players/').doc(self.userInfo.uid).ref
        docRef.get().then(function(doc) {
          if (doc.exists) {
              console.log("Document data:", doc.data());
              let res = doc.data().races
              console.log("res:", res);
              res.forEach(item=>{
                console.log("item:", item);
                console.log(item.id);
                let race = new Race(item.id, item.title, item.progress, item.thumbnail)
                console.log(race);
                self.races.push(race)
              })
              console.log(self.races);

          } else {
              console.log("No such document!");
          }
      }).catch(function(error) {
          console.log("Error getting document:", error);
      });
    }

В этом случае «self используется для сохранения ссылки на исходный this даже при изменении контекста», см. Чтолежит в основе этой идиомы JavaScript: var self = this?

...