I am very new with the MergeMap method to combine multiple API requests. I have following and reading this tutorial how to do it.
https://levelup.gitconnected.com/handle-multiple-api-requests-in-angular-using-mergemap-and-forkjoin-to-avoid-nested-subscriptions-a20fb5040d0c
This is my code to get data from an API:
Service.ts
getPriceList(): Observable<Price[]> {
this.http.get<Price[]>(this.baseUrl).pipe(
map( priceId => {
const id = priceId[0];
this.priceId = id.id;
return id;
}),
mergeMap( Id=> this.http.get(this.baseUrl2 + /${Id.id})),
).subscribe( productPrices => {
this.productPrices = productPrices;
});
}
I need all the data from the first baseUrl, but I assign the Id to use it in my second api request. I call this method in home.ts like this:
this.dataService.getPriceList().subscribe(response => {
console.log(response);
this.priceListData = response;
There is no error when I call this method in the file.
The error is in the method from Service.ts
A function whose declared type is neither 'void' nor 'any' must return
a value.ts(2355)
I am using the return statement in the first api request.
I have tried this solution:
A function whose declared type is neither 'void' nor 'any' must return a value
Then I get the following error:
Type 'Subscription' is missing the following properties from type
'Observable<Crypto[]>': _isScalar, source, operator, lift, and 6
more.ts(2740)
How to use the MergeMap the right way in Angular 11 / ionic 6?
I think you should return something on getPriceList, which you weren't, and if you subscribe inside getPriceList there is no observable anymore to subscribe after that
getPriceList(): Observable<Price[]> {
return this.http
.get<Price[]>(this.baseUrl)
.pipe(
map(priceId => {
const id = priceId[0];
this.priceId = id.id;
return id;
}),
mergeMap(id => this.http.get(`this.baseUrl2${id.id}`))
)
}
and the call
this.dataService.getPriceList().subscribe(response => {
console.log(response);
this.priceListData = response;
});
Related
I recently started developing an app using Flutter and Firebase. I use Firebase Emulator to test Authentication and Cloud Functions. Most of my code is in the Firebase Cloud Functions which I use for all CRUD for Firestore and RTDB. While adding some new features, I got this error in my app. I tried searching a lot but could not find any solution. The following is the error is receive:
An error occured while calling function profile-get
Error Details: null
Message: An internal error has occurred, print and inspect the error details for more information.
Plugin: firebase_functions
Stacktrace: null
My API class in Flutter:
class Api {
Api(this.functions);
final FirebaseFunctions functions;
static Api init() {
FirebaseFunctions functions = FirebaseFunctions.instance;
if (emulator) functions.useFunctionsEmulator(origin: host);
return Api(functions);
}
Future<ApiResult> call(String name, {
Map<String, dynamic> parameters,
}) async {
try {
HttpsCallable callable = functions.httpsCallable(name);
HttpsCallableResult results = await callable.call(parameters);
return ApiResult(new Map<String, dynamic>.from(results.data));
} on FirebaseFunctionsException catch (e) {
print('An error occurred while calling function $name.');
print('Error Details: ${e.details}\nMessage: ${e.message}\nPlugin: ${e.plugin}\nStacktrace: ${e.stackTrace}');
return ApiResult({
'status': 'error',
'message': 'An error occured',
'code': 'unknown'
});
}
}
static String get host => Platform.isAndroid ? 'http://10.0.2.2:2021' : 'http://localhost:2021';
}
I tried running the functions directly from their local URL and they work fine.
As mentioned in the comments defore you are reating a cloud function with onRequest. Those are not callable using an SDK but only trough https URL.
To create a callable function that you can call trough Firebase SDKs you would need to refactor your functions to use the onCall.
It should look something like this:
exports.yourFunctionName= functions.https.onCall((data, context) => {
// receive the data
const text = data.text;
// return a response
return {
test:'test'
}
});
Here you have more information how the callable functions work.
Are you using a different region than the standard us-central1? This is often the case, so you need to change the region you are calling from
HttpsCallable callable = FirebaseFunctions.instanceFor(region:"your_region").httpsCallable(name);
Im working on my first Ionic + Firebase project, and im not understanding this:
Im searching and getting an object from firebase, I can access its details on html and show it to the user.
But now I need to save the createdBy field on that object so I can use it to search for its creator on firebase.
But when I try to access that info its always undefined. Why is that? Any tips on how to fix this?
export class VisitDetailsPage implements OnInit {
public trips: Observable<HomeTripCardsModel>;
public trip: HomeTripCardsModel;
public buddyInfo;
public targetBuddyId: any;
constructor(private router: Router, private navCtrl: NavController,
public fireStorageService: FireStorageService,
private route: ActivatedRoute, public db: AngularFirestore) {
}
ngOnInit() {
const tripId: string = this.route.snapshot.paramMap.get('id');
this.db.collection('users').get()
.subscribe(querySnapshot => {
querySnapshot.forEach(doc => {
this.trips = this.fireStorageService.getTripDetail(tripId, doc.id);
this.trips.forEach((element: HomeTripCardsModel) => {
if (element?.id === tripId) {
this.trip = element;
this.targetBuddyId = element.createdBy;
}
});
});
});
// buddy
console.log(this.trip?.createdBy); // returns undefined
console.log('saved ', this.targetBuddyId) // returns undefined
}}
Data is loaded from Firebase asynchronously. If you set some breakpoints and run in the debugger, or add a log inside the subscribe method, you'll see that your console.log(this.trip?.createdBy) runs before this.trip = element has ever been run. So at that point, it indeed doesn't have a value yet.
For this reason, all code that needs data from the database, needs ot be inside the subscribe callback:
this.db.collection('users').get()
.subscribe(querySnapshot => {
querySnapshot.forEach(doc => {
this.trips = this.fireStorageService.getTripDetail(tripId, doc.id);
this.trips.forEach((element: HomeTripCardsModel) => {
if (element?.id === tripId) {
this.trip = element;
this.targetBuddyId = element.createdBy;
}
});
// buddy
console.log(this.trip?.createdBy); // returns undefined
console.log('saved ', this.targetBuddyId) // returns undefined
});
});
I'm writing an app using React Native and I came across an issue when trying to update an Object with the useState method. Here's my code:
const Screen = ({route}) => {
var roomKey = route.params;
const [room, setRoom] = useState({});
db.ref('rooms').on('value', (data) => {
setRoom(() => (data.val())[roomKey]);
});
console.log(room);
// rest of the code ...
My code works as follows: first it takes a key outputted by another screen with react navigation, and then calls the firebase database with the ref method (db is defined as Firebase.initializeApp(config).database(), where config is the object with all the firebase datas needed). If I log out the data.val())[roomKey] it correctly outputs the object I'm downloading from database, however the room object is not updated by the useState method (it outputs undefined, making the following part of the code crash). What am I doing wrong?
In your code, setRoom is a function to change the value of room state. So, you have to pass the value into the setRoom.
Please check the following code.
const Screen = ({route}) => {
var roomKey = route.params;
const [room, setRoom] = useState({});
db.ref('rooms').on('value', (data) => {
setRoom(data.val()[roomKey]);
});
console.log(room);
// rest of the code ...
I am making an app in ionic 3 and I am trying to fetch data from an url.
This is my code in data.ts and my data provider:
getVehicleStatus() {
return this.http.get<VehicleStatus>(this.url);
}
This is my vehicle class:
class VehicleStatus {
status: string;
plate: string;
code: string;
message: string;
}
I am calling the method into my home.ts file.
ionViewDidLoad() {
console.log(this.getStatus('test3'));
}
getStatus(plate: string) {
this.dataService.getVehicleStatus()
.subscribe((data: VehicleStatus) => this.vehiclestatus = [{ ...data }]);
}
To test out if everything works I hard code a license plate number to log it into my chrome developer tools. It said 'Undefined'.
This is how the json data looks like:
[{"status":"P","plate":"test2","code:"MGP150151","message":"fail"}
,{"status":"P","plate":"test3","code":"MGP160298","message":"fail"}
,{"status":"P","plate":"test4","code":"MGP140085","message":"succes"}
,{"status":"O","plate":"test5","code":"MGP150175","message":"succes"}]
I should get this object back:
{"status":"P","plate":"test3","code":"MGP160298","message":"fail"}
But it doesn't work and got the message undefined.
I have used the following source:
https://angular.io/guide/http
How can I search in the array and bind it to my HTML page in ionic 3?.
Can someone point me in the right direction?.
Kind regards .
The responsibility to find the VehicleStatus from the list should be of the service rather than of the Component itself.
Consider changing your Service Implementation to take up that responsibility. You can use the map operator to transform the response to return the VehicleStatus found based on the plate that will be passed as an arg while calling the getVehicleStatus method.
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
getVehicleStatus(plate): Observable<VehicleStatus> {
return this.http.get<VehicleStatus[]>(this.url)
.pipe(
map(statuses => statuses.find(status => status.plate === plate))
);
}
Then in your home.ts:
ionViewDidLoad() {
this.getStatus('test3');
}
getStatus(plate: string) {
this.dataService.getVehicleStatus(plate)
.subscribe((data: VehicleStatus) => this.vehiclestatus = data);
}
You need array.find to get the matching value, which will return the first matching element from the array
this.vehiclestatus = data.find(vehicle=>vehicle.plate === plate);
I am building an Android app and I am struggling using the AsyncStorage. I want to create a function that takes a key as input and give me back the item. My problem is that when I call this function, it returns { _40: 0, _65: 0, _55: null, _72: null } instead the value I am looking for.
Here is my code :
renderList() {
async function save() {
await AsyncStorage.setItem('Title', 'hello');
}
async function fetch(key) {
const value = await AsyncStorage.getItem(key);
console.log(value) ; // Return hello
return value
}
save() ;
fetch() ;
const reponse = fetch() ;
console.log(reponse) ; // Return { _40: 0, _65: 0, _55: null, _72: null }
return (
<Text style={styles.noteElementTitle}> Aa </Text>
)
}
Edit :
I tried this :
async function getBody() {
await save();
const response = await fetch('Title');
console.log(response);
this.setstate({ title : response}) ;
}
getBody() ;
But I still get an error : TypeError: undefined is not a function (evaluating 'this.setstate({ title: response })')
What you're seeing is the Promise object returned by a function marked async. You need to either use await when calling the function, or treat the value as a promise and use then and catch. For example:
await save();
const response = await fetch();
console.log(response);
or
save()
.then(() => fetch())
.then(response => console.log(response));
Also, keep in mind that you should not be using async functions inside a render function. In your code above, you'll want to put the result of your fetch() function into component state.