I'm trying to clean up my Ionic app and move redundant functions into a provider. Below is an example of what most of my API functions look like (except I've stripped out a lot of irrelevant stuff for brevity) and they are working perfectly.
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 => { });
});
}
So what I've done is move the function into the provider and changed it like so
getDataFromApi() {
....
Promise.all([
...
]).then((result) => {
let headers = new Headers();
...
let body = new FormData();
...
return this.http.post(url, body, headers));
});
}
And then inside the page's constructor I'm calling it like this
this.service.getDataFromApi()
.map(res => res.json())
.subscribe(data => {
if (data == '{}') {
this.mydata = [];
} else {
this.mydata = data;
}
}, error => { });
Obviously that's not working. I've been pouring over SO posts for 2 days now and can't get other people's examples and answers to work properly either. I've tried mapping in the provider and subscribing when calling it in the page, but no matter what I try just keep receiving errors. I know this function is returning data because I can see it before moving it into the provider.
What am I doing wrong?
I think the most important thing is to be consistent; you can do all that using only promises or using only observables (instead of mixing both).
Please take a look at this stackblitz demo where you can see how to make a similar HTTP request by using only observables and the exact same request using only promises.
You can use switchMap (or any other flattening operator) together with fromPromise to handle all that in the same method from your provider:
// 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);
}
And then you'd use it like this:
this.dataService.getDataUsingObservables().subscribe(
response => {
this.responseUsingObservables = response;
},
error => {
// Handle the error...
alert(error);
});
If you want to use promises, you can use the toPromise() operator to transform the observable into a promise:
// 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);
}
And then you'd use it like this:
this.dataService.getDataUsingPromises()
.then(response => {
this.responseUsingPromises = response;
})
.catch(error => {
// Handle the error...
alert(error);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With