Flutter: Cannot store Firestore data to local variable (returns null) - flutter

I have an issue when trying to store data from Firestore to a local variable.
class AppUser {
String _userId;
Map<String, dynamic> _userData;
Future getUserDataFromDb() async {
_userData = await dbInterface.getFinancialsFromDB(_userId);
// dbInterface.getFinancialsFromDB(_userId).then((Map<String, dynamic> data) {
// _userData = data;
// });
print(_userData); // flutter: null
}
}
_userData always returns null.
class Db {
CollectionReference financials = FirebaseFirestore.instance.collection('financials');
Future<Map<String, dynamic>> getFinancialsFromDB(userId) async {
financials.doc(userId).get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
print(documentSnapshot.data()); // flutter: {'key1': 'data1', ...}
return documentSnapshot.data();
}
});
return null;
}
}
Db dbInterface = Db();
Within the "getFinancialsFromDB"-Function it prints the correct Map. So the issue isn't to retrieve the data from Firestore but to store it in the _userData variable.
The getUserDataFromDb() is called in an initState.
Any ideas what I could do to fix this issue? If you need any additional infos please let me know.
Thanks a lot, I really appreciate any help.
All the best,
Alex

When writing code an in async function, don't use then. Instead, use await to get the result of a Future.
Future<Map<String, dynamic>> getFinancialsFromDB(userId) async {
var documentSnapshot = await financials.doc(userId).get();
if (documentSnapshot.exists) {
return documentSnapshot.data();
}
else {
return null;
}
}

Related

How to fetch data without retrieve to widgets in flutter?

In my code I want fetch data to backend without show in ui. Data getting from API, andaslo for that I use model class that same model and API call I used to fetch data and show in UI. That's work without any errors.But in this page I want get doctor_in vale is true or false from that same model and API call method.
model class
class DataDoctor {
String appId;
String channelName;
String receiver_name;
bool doctor_in;
DataDoctor(
{required this.appId,
required this.channelName,
required this.receiver_name,
required this.doctor_in});
factory DataDoctor.fromJson(Map<String, dynamic> json) {
return DataDoctor(
appId: json['appId'] == null ? null : json['appId'],
channelName: json['channelName'] == null ? null : json['channelName'],
receiver_name:
json['receiver_name'] == null ? null : json['receiver_name'],
doctor_in: json['doctor_in'] == null ? null : json['doctor_in'],
);
}
}
using this model I want get doctor_in boolean value
to the getDoctorActive() method
getDoctorActive() method
void getDoctorActive() {
Map<String, dynamic> jsonData =
json.decode(jsonDataAsString) as Map<String, dynamic>;
doctor_in.value = jsonData['doctor_in'].toString(); }
error
How to get data without show in UI in flutter?
API code
import 'dart:convert';
import 'package:http/http.dart';
import '../model/appIdModel.dart';
class ApiService {
loadData(String channelName) async {
final String url ='https://jsonplaceholder.typicode.com/posts/1=$channelName';
Future<List<Data>> getData() async {
Response response = await get(Uri.parse(url));
if (response.statusCode == 2000) {
Map<String, dynamic> json = jsonDecode(response.body);
List<dynamic> body = json['data'];
List<Data> datas = body.map((dynamic item) => Data.fromJson(item).toList();
return datas;
} else {
throw ('cannot fetch data');
}
}
}
}
initState
Timer? timer;
bool doctor_in = false;
#override
void initState() {
super.initState();
getDoctorActive();
timer =
Timer.periodic(Duration(seconds: 15), (Timer t) => checkDoctorActive());
}
checkDoctorActive
Future<void> checkDoctorActive() async {
if (doctor_in == true) {
future = client.getData(widget.channelName);
}
}
errors
API call
If you want to periodically fetch data in the background without updating the UI, you can create a class for that purpose, like this
class DoctorCheck{
Future<bool> isDoctorActive(String channelName) async {
// do the api call here as shown in the line below
// var jsonResponse = await client.getData(widget.channelName)
return Data.fromJson(jsonResponse).doctor_in == true;
}
}
And call it wherever you want, like this
bool isDoctorActive = await DoctorCheck().isDoctorActive(channelName);
It will return a bool whether the doctor is active or not.
Put it in a function like this
Future<void> dr() async {
bool isDrActive = await DoctorCheck().isDoctorActive(channelName);
setState(() { doctor_in = isDrActive; });
}
Whenever you call dr(), your variable doctor_in will be updated with the latest value of whether doctor is active or not.
From #rrttrr answer with a change
class DoctorCheck{
Future<bool> isDoctorActive(String channelName) async {
return Data.fromJson(json).doctor_in == true; // Change jsonResponse to json
}
}

Future not waiting to resolve before next then Flutter Dart

I'm trying to return a list of values.
Assessing by using Late
late List userLikes = userListLikes.getUsersLikes();
My Code:
class GetUserLikes {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final user = FirebaseAuth.instance.currentUser!;
List getUsersLikes() {
try {
print('start');
final docRef = _firestore.collection("user_details").doc(user.uid);
docRef.get().then((DocumentSnapshot doc) async {
final data = doc.data() as Map<String, dynamic>;
print("data[user_likes]");
print(data['user_likes']);
print('end');
return await data['user_likes']; // → not awaiting
},
onError: (e) => print("Error getting document: $e"),
);
} catch (err) {
print('There was an error');
}
return ['Nothing Returned'];
}
}
The function is not completing and returns before the await has finished which is not the array I need.
start
[Nothing Returned] (Returns without completing)
data[user_likes]
[967, 769, 887, 820, 860, 833, 857, 1017] → The Array I want returned
end
As someone downvoted this answer here is the full working code:
This get an Array field from a Firestone database and then returns a list dynamic.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class GetUserLikes {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final user = FirebaseAuth.instance.currentUser!;
Future<List> getUsersLikes() async {
// Get the list of user likes from the Firestone Database and then
// return the list so it will only show the users likes on the profile page.
try {
final docRef = _firestore.collection("user_details").doc(user.uid);
DocumentSnapshot doc = await docRef.get(); // Await
final data = doc.data() as Map<String, dynamic>;
return data['user_likes'];
} catch (err) {
print('There was an error');
}
return ['Nothing Returned'];
}
Future<List> getLikes() async {
// Takes the Future<List> and turns it into a List<dynamic>
Future<List> userLikes = getUsersLikes();
List list = await userLikes;
return list; // Returns List<dynamic>
}
}
Then on the receiving Future builder it will have to be awaited.
GetUserLikes userLikesList = GetUserLikes();
List userLikes = await userLikesList.getLikes();

Type Conversion issue Flutter - Convert from Future<List<Dog>?> to List<Dog>

Below is the method to retrieve a list of data from local sqlite table:
Future<List<Dog>?> retriveDogs() async {
return await _dbHelper?.dogs();
}
and you can check dogs() method as below :
Future<List<Dog>> dogs() async {
final db = await database;
final List<Map<String, dynamic>> maps = await db.query('dogs');
return List.generate(maps.length, (i) {
return Dog(
id: maps[i]['id'],
name: maps[i]['name'],
age: maps[i]['age'],
);
});
}
I want to display list in my log or via print statement.
So, I have done as below :
print(" >>> "+retriveDogs().toString());
But it gives me as :
>> Instance of 'Future<List?> after print..
How can I get the complete list of Dogs ? Thanks.
Your retriveDogs can retune null value. You can pass empty list for null cases like.
Future<List<Dog>> retriveDogs() async {
return await _dbHelper?.dogs()??[];
}
and to get data from future, you can use await or .then
onPressed: () async {
final data = await retriveDogs();
print(data.toString());
},
retriveDogs().then((value) => print(value));

How to get name and phone number from realtime database in flutter?

I have one user in my database:
Users {
userId: Xx1j9Pih4BPnu01vnFdMfZqGOr02: {name: 'jack5' ,phone: '0845204281'
}
}
So far I have the following function for getting data from the realtime firebase database.
static Future<dynamic> getCurrentUserInfo() async {
String? userId = FirebaseAuth.instance.currentUser?.uid;
final ref = FirebaseDatabase.instance.ref();
final snapshot = await ref.child('users/$userId').get();
if (snapshot.exists) {
return snapshot.value;
} else {
print('No data available.');
return '';
}
The function returns an object. How do I convert this object into a string? Or: How do I simply get the name of the current user of my database?
static Future<dynamic> getCurrentUserInfo() async {
String? userId = FirebaseAuth.instance.currentUser?.uid;
final ref = FirebaseDatabase.instance.ref();
final snapshot = await ref.child('users/$userId').get();
if (snapshot.exists) {
Map<dynamic, dynamic> values = needsSnapshot.value;
values.forEach((key, values) {
print(values['name']);
print(values['phone']);
});
} else {
print('No data available.');
return '';
}
}
If you just want to get the name property of the user, assuming your users are stored by their UID, that'd be:
final snapshot = await ref.child('users/$userId/name').get();
print(snapshot.value);

Getting document from Firestore to pun inside a Custom User profile but it returns null. Dart/Flutter

Hi there I'm having some trouble to retrieve data from Firestore;
I created a class User for getting all the information for my app.
User Class:
class User {
String id;
String displayName;
String email;
String pictureURL;
String gender;
DateTime dateOfBirth;
User(fbauth.User user) {
id = user.uid;
displayName = user.displayName;
email = user.email;
pictureURL = user.photoURL;
// setting info
DocumentSnapshot resl = FirestoreUtil.read("AdditionalUserInfo", user.uid);
gender = resl.data()['gender'];
dateOfBirth = (resl.data()['date of birth'] as Timestamp).toDate();
}
FirestoreUtils class:
class FirestoreUtil {
static DocumentSnapshot read(String collection, String document) {
FirebaseFirestore.instance
.collection(collection)
.doc(document)
.get()
.then((DocumentSnapshot snapshot) {
if(snapshot.exists){
return snapshot;
}else{
print("no data found");
}
});
}
}
After I return the snapshot, it gets null. But if I do this it prints out the correct values:
class FirestoreUtil {
static DocumentSnapshot read(String collection, String document) {
FirebaseFirestore.instance
.collection(collection)
.doc(document)
.get()
.then((DocumentSnapshot snapshot) {
if(snapshot.exists){
print(snapshot.data);
}else{
print("no data found");
}
});
}
}
I tried literally everything but I couldn't figure out. Could someone help? I cannot imagine that is that hard to retrieve data inside a class.
It's probably Future(async/await) problem. You are returning value inside Future, you can get this value inside another then() etc.
class FirestoreUtil {
static DocumentSnapshot read(String collection, String document) async {
// You can directly return it too without assigning it to result variable
var result = await FirebaseFirestore.instance
.collection(collection)
.doc(document)
.get();
return result;
}
}
There is data() method for DocumentSnapshot, you can use result.data() and check if it's null, isEmpty etc.
I wrote this function with async/await but if you need Future and didn't want to wait operation to be finished, you can directly return
FirebaseFirestore.instance.collection(collection).doc(document).get();
and you can use then() after you get the Future.