Угловая подписка на данные, возвращаемые из API - PullRequest
0 голосов
/ 28 сентября 2018

Я пытаюсь очистить свое приложение Ionic и перенести избыточные функции в поставщика.Ниже приведен пример того, как выглядит большинство моих API-функций (за исключением того, что для краткости я убрал много ненужных вещей), и они работают отлично.

getDataFromApi() {
    ....
    Promise.all([
        ...
    ]).then((result) => {
        let headers = new Headers();
        ...
        let body = new FormData();
        ...
        this.http.post(url, body, headers)
            .map(res => res.json())
            .subscribe(data => {
                if (data == '{}') {
                    this.mydata = [];
                } else {
                    this.mydata = data;
                }
            }, error => { });
    });
}

Итак, я сделал этопереместите функцию в провайдер и измените ее следующим образом:

getDataFromApi() {
    ....
    Promise.all([
        ...
    ]).then((result) => {
        let headers = new Headers();
        ...
        let body = new FormData();
        ...
        return this.http.post(url, body, headers));
    });
}

И затем внутри конструктора страницы я называю это следующим образом

this.service.getDataFromApi()
    .map(res => res.json())
    .subscribe(data => {
        if (data == '{}') {
            this.mydata = [];
        } else {
            this.mydata = data;
        }
    }, error => { });

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

Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 28 сентября 2018

Я думаю, что самое главное, чтобы быть последовательным;Вы можете сделать все это, используя только обещания или только наблюдаемые (вместо того, чтобы смешать оба).

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


Используя наблюдаемые

Вы можетеиспользуйте switchMap (или любой другой оператор выравнивания) вместе с fromPromise для обработки всего этого тем же методом от вашего провайдера:

// Angular
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

// RxJS 
// Please notice that this demo uses the 5.5.2 version
import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators/map';
import { tap } from 'rxjs/operators/tap';
import { switchMap } from 'rxjs/operators/switchMap';

// ...

// Get a list of 5 users using observables
public getDataUsingObservables(): Observable<any> {
  const promises = Promise.all([
    this.somePromise('getDataUsingObservables', 1),
    this.somePromise('getDataUsingObservables', 2)
  ]);

  return fromPromise(promises)
    .pipe(
      switchMap(results => {
        console.log(`[getDataUsingObservables]: Both promises are finished`);
        const url = `https://randomuser.me/api/?results=5`;

        return this.http.get<any>(url);
      }),
      tap(res => {
        console.log(`[getDataUsingObservables]: The http request is finished`);
      })
  );
}

// Return a promise with the number sent as parameter 
private somePromise(callerMethod: string, aNumber: number): Promise<number> {
  console.log(`[${callerMethod}]: About to create a promise with the number ${aNumber}`);
  return Promise.resolve(aNumber);
}

И тогда вы будете использовать его так:

this.dataService.getDataUsingObservables().subscribe(
  response => {
    this.responseUsingObservables = response;
  }, 
  error => {
    // Handle the error...
    alert(error);
  });

Использование обещаний

Если вы хотите использовать обещания, вы можете использовать оператор toPromise() для преобразования наблюдаемого в обещание:

// Angular
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

// RxJS 
// Please notice that this demo uses the 5.5.2 version
import { tap } from 'rxjs/operators/tap';

// ...

// Get a list of 5 users using promises
public getDataUsingPromises(): Promise<any> {
  const promises = Promise.all([
      this.somePromise('getDataUsingPromises', 1),
      this.somePromise('getDataUsingPromises', 2)
  ]);

  return promises
    .then(results => {
      console.log(`[getDataUsingPromises]: Both promises are finished`);
      const url = `https://randomuser.me/api/?results=5`;

      return this.http.get<any>(url)
        .pipe(
          tap(res => {
            console.log(`[getDataUsingPromises]: The http request is finished`);
          })
        )
        .toPromise();
    });
}

// Return a promise with the number sent as parameter 
private somePromise(callerMethod: string, aNumber: number): Promise<number> {
  console.log(`[${callerMethod}]: About to create a promise with the number ${aNumber}`);
  return Promise.resolve(aNumber);
}

Итогда вы будете использовать это так:

this.dataService.getDataUsingPromises()
  .then(response => {
    this.responseUsingPromises = response;
  })
  .catch(error => {
    // Handle the error...
    alert(error);
  });
0 голосов
/ 28 сентября 2018

Disclamer : Может быть / должен быть способ реализовать точно такую ​​же концепцию в наблюдаемых, но я не слишком знаком с ними, поэтому, возможно, кто-то может уточнить.

Вашфункция должна возвращать обещание, что означает, что вы должны выполнить

getDataFromApi() {
    ....
    return Promise.all([
        ...
    ]);
}

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

Для этого ваша функция должна по-прежнему возвращать обещание, которое разрешается после требуемого оператора возврата, например так:

getDataFromApi() {
  ....
  new Promise((resolve, reject) => {
    Promise.all([
      ...
    ]).then(result => {
      const headers = new Headers();
      ...
      const body = new FormData();
      ...
      // This is equavilent to your desired return
      resolve(this.http.post(url, body, headers));
    });
  });
}

, а затем реализовать подписку POST в блоке вызывающего then, например:так:

this.service.getDataFromApi()
  .then(observ => {
    observ.subscribe(result => {
    // Use your response here
    });
  });

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

Редактировать: Еще лучше, если каждый раз, когда вы просто подписываетесь на данные JSON и хотите, чтобы они возвращалиськонцепцию можно обобщить, чтобы сделать код в вызывающей стороне более лаконичным:

this.service.getDataFromApi().then(finalData => {
  // This is the final returned data ...
}, (err) => {
//allows error to be handled
});

Это может быть достигнуто путем разрешения обещания в методеайдеров в блоке подписки следующим образом:

getDataFromApi() {
  return new Promise((resolve, reject) => {
    Promise.all([...]).then(result => {
      const headers = new Headers();
      const body = new FormData();
      this.http
        .post(url, body, headers)
        .map(res => res.json())
        .subscribe(data => {
          if (data == '{}') {
            reject([]);
          } else {
            resolve(data);
          }
        });
    });  
  })
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...