First, apologies I am a total newb to Flutter, Dart & Firestore and despite trying to follow many tutorials I am stuck.
I am trying to retrieve a Firestore collection record by a specific value.
I have a service dart class which runs the query.
import 'package:cloud_firestore/cloud_firestore.dart';
class WaypointService {
getWaypointById(int wpCheckPointId) {
return FirebaseFirestore.instance
.collection("waypoints")
.where("CheckPoint", isEqualTo: wpCheckPointId)
.get();
}
}
This service is passed an integer from a constant in a constants file. The screen that calls the service is:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:lhgth/services/waypoint_service.dart';
class WaypointScreen extends StatelessWidget {
const WaypointScreen({ super.key, required this.wpFirebaseID });
final int wpFirebaseID;
@override
Widget build(BuildContext context) {
var waypoint;
WaypointService().getWaypointById(wpFirebaseID).then((QuerySnapshot wayPoint) {
if (wayPoint.docs.isNotEmpty) {
waypoint = wayPoint.docs.first.data();
print(waypoint); //##1
}
});
print(waypoint); //##2
return Container(
padding: EdgeInsets.all(8),
child: Scaffold(
backgroundColor: Colors.white,
body: Container(
),
)
);
}
}
The issue I have is that the print statement ##1
is outputting what looks to be a JSON value:
{
Radius: 25,
Long: 50.9491835,
Info: Text,
Lat: 0.7317906,
CheckPoint: 1,
Name: Waypoint Name
}
However, the second print ##2
returns a NULL
and so I am not sure how I would work with the data returned from the query in the view itself.
Any guidance would be helpful.
>Solution :
That’s totally normal, the get() method is an async method you have to wait before it returns the value.
The second print ##2 returns null because it called before the getWaypointById method finishes.
First: make your getWaypointById method as Future like this:
Future<QuerySnapshot> getWaypointById(int wpCheckPointId) {
return FirebaseFirestore.instance
.collection("waypoints")
.where("CheckPoint", isEqualTo: wpCheckPointId)
.get();
}
Then: instead of doing tests in the build method, you can test in an external method like this:
test() async {
var waypoint;
var results = await getWaypointById(wpFirebaseID);
if (results.docs.isNotEmpty) {
waypoint = results.docs.first.data();
}
print(waypoint);
}
Then you can call the test method in the build.
To show the value on the screen you can use FutureBuilder:
class WaypointScreen extends StatelessWidget {
const WaypointScreen({ super.key, required this.wpFirebaseID });
final int wpFirebaseID;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8),
child: Scaffold(
backgroundColor: Colors.white,
body: Container(
child: FutureBuilder<QuerySnapshot>(
future: WaypointService().getWaypointById(wpFirebaseID),
builder: (context, snapshot) {
if (snapshot.hasData && (snapshot.data?.docs.isNotEmpty?? false)) {
var waypoint = snapshot.data!.docs.first.data();
return Text(waypoint['Name']);
} else {
return Text('Loading...');
}
},
),
),
)
);
}
}