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

Я использую Ангуляр 8.

Я создал функцию с именем getUserInfo() в классе обслуживания, которая возвращает информацию о пользователе, использующем облачный сервис Firestore.

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

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

RxJS исправляет это?

Я уже пробовал Router Resolver, но это тоже не сработало.

Это функция, которую я использую в классе обслуживания

getUserInfo() {
    this.db.collection('users').doc(`${this.cookie.get("id")}`).ref.get().then(doc => {
    return doc.data()
})}

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

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../auth/auth.service';

@Component({
    selector: 'app-super-admin',
    templateUrl: './super-admin.component.html',
    styleUrls: ['./super-admin.component.css']
})
export class SuperAdminComponent implements OnInit {
    user;
    constructor(private authService: AuthService) { }

    ngOnInit() {
        this.user = this.authService.getUserInfo();
    }
}

person Shakar Bakr    schedule 26.09.2019    source источник
comment
Пробовали ли вы асинхронный канал в представлении компонентов ‹span›{{ user | асинхронный }}‹/span›   -  person Adi    schedule 26.09.2019
comment
@Adi, да, но все равно выдает ошибку Undefined   -  person Shakar Bakr    schedule 26.09.2019


Ответы (4)


Лучше использовать Rxjs только потому, что он обычно используется с angular, поэтому я определенно рекомендую это. Однако, если вы ищете решения без него, вы всегда можете использовать промисы.
Итак, проблема, с которой вы столкнулись, заключается в том, что код выполняется до того, как данные получены с сервера. Вы можете исправить это, промисив свой вызов firestore внутри службы и вернув промис, после чего вы можете вызвать промис внутри вашего компонента.
Таким образом, код становится таким: Класс службы

getUserInfo() {
let promise =  new Promise( (resolve,reject) => {
    this.db.collection('users').doc(`${this.cookie.get("id")}`).ref.get().then(doc => {
      resolve(doc.data());
    }).catch(er => {
      reject(er);
    })
}
return promise;
);

Затем в файле компонента ts вы можете сделать:

   ngOnInit() {
        this.authService.getUserInfo().then(data => {
          this.user = data;
        });
    }

Надеюсь это поможет!

person Muhammad Hamza Shujaat    schedule 26.09.2019
comment
Спасибоуууууууу - person Shakar Bakr; 27.09.2019

this.user = this.authService.getUserInfo();

Да, ты прав. На данный момент authService.getUserInfo() еще не разрешен. (Кроме того, в вашем методе getUserInfo() нет инструкции return).

Я могу придумать 2 способа решить эту проблему.

this.authService.getUserInfo().then(u => this.user = u);

Способ RxJS:

getUserInfo() {
 return from(this.db.collection('users').doc(`${this.cookie.get("id")}`).ref.get());
}

/* ... */

this.authService.getUserInfo()
 .subscribe(u => this.user = u);

Здесь подробнее о том, как преобразовать обещание в наблюдаемое.

person Andrei Gătej    schedule 26.09.2019
comment
ни один не исправил! первый способ дает мне ошибку, когда я добавляю затем к this.authService.getUserInfo() и говорит, что свойство тогда не существует для типа void, а для второго, который я попробовал ваш код, он говорит то же самое. кстати, я ничего не знаю о RxJS :( поэтому я был бы признателен за любое решение без него - person Shakar Bakr; 26.09.2019

Короткий ответ: да, RxJS решает вашу проблему.

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

Ваш компонент должен подписаться на этот асинхронный ответ и выполнять требуемое действие только при получении ответа.

Итак, вам нужно избавиться от обещания в вашем сервисе и просто вернуть вызов в материал Firebase.

getUserInfo() {
    return this.db.collection('users').doc(`${this.cookie.get("id")}`).ref.get();
}

В то время как в вашем компоненте вам нужно сделать что-то вроде этого:

ngOnInit() {
    this.authService.getUserInfo().subscribe(response => {
        /* Use `response` as the answer from the server and do whatever you need to do */
        console.log(response); // Use this to inspect the response from the server
    });
}
person Ferie    schedule 26.09.2019
comment
это дает мне ошибку: подписка на свойство не существует для типа void :( - person Shakar Bakr; 26.09.2019
comment
Ваш сервис должен return что-то делать, поэтому проверьте код. Эта ошибка возникает, если вы ничего не возвращаете из нее. - person Ferie; 26.09.2019
comment
я делал это раньше, но эта консоль предназначена только для того, чтобы показать мне данные внутри службы, поэтому даже когда я возвращаю данные, она выдает мне ошибку, которую я сказал. эта консоль предназначена только для тестирования, чтобы увидеть, есть ли в ней данные или нет - person Shakar Bakr; 26.09.2019
comment
Предоставьте пример Stackblitz, чтобы мы проверили ваш код stackblitz.com - person Ferie; 26.09.2019
comment
@Ferie, этот код будет работать, только если this.db.collection('users').doc(`${this.cookie.get("id")}`).ref.get(); возвращает наблюдаемое, чего он может не делать. Поскольку это не вызов модуля HttpClient angular. - person Muhammad Hamza Shujaat; 29.09.2019

Я воссоздал ваш сценарий в этом stackblitz, он работает хорошо

util.service.ts

import { Injectable } from '@angular/core';

@Injectable()
export class UtilService {

  constructor() { }

  getUserInfo() {
    return new Promise((res,rej) => {
      this.getDelayedData((data) => {
        res(data)
      });
    });
  }

  getDelayedData(call){
   setTimeout(()=> {
     call('here your data');
    }, 1500)
  }
}

app.component.ts

import { Component } from '@angular/core';
import { UtilService } from './util.service';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';
  constructor(public util: UtilService) {
    this.util.getUserInfo().then((data : string) => {
      this.name = data;
      console.log(data)
    })
  }
}
person Raghul Selvam    schedule 26.09.2019