Data is repeated in Flutter UI when reading from Firestore - flutter

I'm having a problem where data is repeated in my UI:
I'm putting the code but is giving it to me 3 times, how can I solve this?
code:
`
class GetUserName extends StatelessWidget {
final String documentId;
const GetUserName({Key? key, required this.documentId}) : super(key: key);
#override
Widget build(BuildContext context) {
// Get the collection
CollectionReference user = FirebaseFirestore.instance.collection('users');
return FutureBuilder<DocumentSnapshot>(
future: user.doc(documentId).get(),
builder: ((context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Text(
"User Full Name: \n${data['first name']} ${data['last name']}");
}
return const Text('Loading...');
}),
);
}
}
`
I tried to put the user information and it is givving me this error so I have not space and I don't know how to divide them.

Related

When try to fetch data from firebase - null check operator used on a null value - Flutter

I'm trying to fetch data from firestore and display them.
When I call VendorModel vendor = VendorModel.fromJson(snapshot.data!() as Map<String, dynamic>);
it throws me an exception saying...
null check operator used on a null value
Here are my files
vander_home.dart
class VendorHome extends StatelessWidget {
const VendorHome({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final FirebaseService _service = FirebaseService();
return StreamBuilder<DocumentSnapshot>(
stream: _service.vendor.doc(_service.user!.uid).snapshots(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator(
color: Colors.red,
);
}
VendorModel vendor =
VendorModel.fromJson(snapshot.data!() as Map<String, dynamic>);
return Text(
vendor.businessName!,
);
},
);
}
}
vander_model.dart
class VendorModel {
VendorModel({
this.businessName,
});
VendorModel.fromJson(Map<String, Object?> json)
: this(
businessName: json['businessName']! as String,
);
final String? businessName;
Map<String, Object?> toJson() {
return {
'businessName': businessName,
};
}
}
firebase_service.dart
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
class FirebaseService {
User? user = FirebaseAuth.instance.currentUser;
final CollectionReference vendor =
FirebaseFirestore.instance.collection('vendor');
firebase_storage.FirebaseStorage storage =
firebase_storage.FirebaseStorage.instance;
Future<void> addVendor({Map<String, dynamic>? data}) {
return vendor.doc(user!.uid).set(data);
}
}
How to solve this?
I found a way to do this.
But anyone can help me to how go through my above problem please help me.
class VendorHome extends StatelessWidget {
const VendorHome({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final FirebaseService _service = FirebaseService();
return StreamBuilder<DocumentSnapshot>(
stream: _service.vendor.doc(_service.user!.uid).snapshots(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator(
color: Colors.red,
);
}
if (!snapshot.data!.exists) {
return const BusinessRegisterScreen();
}
var docc = snapshot.data;
return Text(
docc!['businessName'],
);
},
);
}
}
Without using VendorModel...
Thank you.
You are using ! on null value, so change this :
VendorModel vendor = VendorModel.fromJson(snapshot.data!() as Map<String, dynamic>);
to this:
VendorModel vendor = VendorModel.fromJson( snapshot.data == null ? {}: snapshot.data as Map<String, dynamic>);
also in your VendorModel model class change this:
VendorModel.fromJson(Map<String, Object?> json)
: this(
businessName: json['businessName']! as String,
);
to
VendorModel.fromJson(Map<String, Object?> json)
: this(
businessName: json['businessName'] != null ? json['businessName'] as String : "",
);

Fetch field from firestore as String in flutter

I want to fetch a field value from firestore and assign it to String variable.
So how can I do this?
When I fetch data it comes as a map.
So in which way I can fetch data as string
screena.dart
class ScreenA extends StatefulWidget {
const ScreenA({Key? key}) : super(key: key);
#override
State<ScreenA> createState() => _ScreenAState();
}
class _ScreenAState extends State<ScreenA> {
List<String> docIDs = [];
Future getDocId() async {
final userId = AuthService.firebase().currentUser!.id;
await FirebaseFirestore.instance
.collection('user')
.where('user_id', isEqualTo: userId)
.get()
.then(
(snapshot) => snapshot.docs.forEach(
(document) {
docIDs.add(document.reference.id);
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: getDocId(),
builder: (context, snapshot) {
return ListView.builder(
shrinkWrap: true,
itemCount: docIDs.length,
itemBuilder: (context, index) {
return ListTile(title: Gettt(docId: docIDs[index]));
},
);
},
),
);
}
}
gettt.dart
class Gettt extends StatelessWidget {
final String docId;
Gettt({Key? key, required this.docId}) : super(key: key);
#override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection('user');
return FutureBuilder<DocumentSnapshot>(
future: users.doc(docId).get(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Text('Locker Id: ${data['first_name']}');
}
return const Text('Loading');
},
);
}
}
here's my code
sorry for the last time
I can get a list of items
But I want to without getting a widget I need to get a String
How to do it?
after get document, you can get field example[dart]:

Flutter - display field - name - of user that is logged in

Im trying to display name of user that is currently logged in app. I have this code right now but its showing me "Document does not exist". I have it from other person that was asking here on stackoverflow but they figured it somehow but didnt post the full correct code so im asking here again. Link Retrieve one field from firebase and display it in a Text Widget
class ProfilePage extends StatefulWidget {
const ProfilePage({Key? key}) : super(key: key);
#override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
DocumentReference userName = FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid);
//Variable used to store the name
String name = '';
#override
void initState() {
super.initState();
userName.get().then((DocumentSnapshot ds) {
name = ds['name'];
});
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
FutureBuilder<DocumentSnapshot>(
future: userName.get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return const Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
return Text("Full Name: ${data['name']}");
}
return const Text("loading");
},
)
],
),
);
}
}
First make sure that "FirebaseAuth.instance.currentUser!.uid" doesn't give null and there is an internet connection.
Then, there are two ways:
Do the following function, and call it in initState method
Future<void> getUserData(String userID) async {
DocumentReference authResult =
FirebaseFirestore.instance.collection('users').doc(userID);
DocumentSnapshot docSnap = await authResult.get();
var data = docSnap.data() as Map<String, dynamic>;
name = data['name'];
}
when you call this function, pass the userId as an argument to the function
OR
Instead of implementing a function and call it in initState you can call didChangeDependencies and make it async
#override
void didChangeDependencies() async {
super.didChangeDependencies();
DocumentReference authResult =
FirebaseFirestore.instance.collection('users').doc(userID);
DocumentSnapshot docSnap = await authResult.get();
var data = docSnap.data() as Map<String, dynamic>;
name = data['name'];
}
Edit
class ProfilePage extends StatefulWidget {
const ProfilePage({Key? key}) : super(key: key);
#override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
DocumentReference userName = FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid);
//Variable used to store the name
String name = '';
#override
void didChangeDependencies() async {
super.didChangeDependencies();
DocumentReference authResult =
FirebaseFirestore.instance.collection('users').doc(FirebaseAuth.instance.currentUser!.uid);
DocumentSnapshot docSnap = await authResult.get();
var data = docSnap.data() as Map<String, dynamic>;
name = data['name'];
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
FutureBuilder<DocumentSnapshot>(
future: userName.get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return const Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
return Text("Full Name: ${data['name']}");
}
return const Text("loading");
},
)
],
),
);
}
}

Error: A value of type 'Future<ListView>' can't be returned from a function with return type 'Widget'

I'm tryng to read data from Cloud Firestore (working) and put the data in a ListView containing a graphic widget (Order) that shows price, date and product, but when I'm trying to return the data from the method this error shows up.
The target is to return the data of the user passed to the db_utility constructor.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'order.dart';
class db_utility extends StatelessWidget {
final String userID;
const db_utility(this.userID, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection('users');
return FutureBuilder(
future: users.doc(userID).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text("error");
} else if (snapshot.hasData && !snapshot.data!.exists) {
return const Text("no data found");
} else if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return getListOfOrders();
}
return const Center(
child: CircularProgressIndicator(
color: Colors.red,
),
);
},
);
}
And this is the method that returns the ListView:
Future<ListView> getListOfOrders() async {
QuerySnapshot snapshot = await FirebaseFirestore.instance
.collection('completed_orders')
.where('user', isEqualTo: userID)
.orderBy('timestamp')
.get();
final data = snapshot.docs.map((doc) => doc.data()).toList();
List<Order> orders = <Order>[];
for (var o in data) {
orders.add(Order((o as Map)['price'], 'date of today', o['product']));
}
return ListView(children: orders,);
}
}
getListOfOrders() is another future method, you can use nested FutureBuilder .
In that case, instead of return getListOfOrders(); use another FutureBuilder like previous one. But you can do the operation on single future method.
You can also check multiple method on a future builder

Flutter FutureBuilder snapshot returns Instance of 'Object' instead of data

i am new to flutter and trying to display data from a http post
referencing from [1]https://flutter.dev/docs/cookbook/networking/background-parsing and [2]https://flutter.dev/docs/cookbook/networking/fetch-data
i tried to display data on a futurebuilder but it keeps displaying this from the Text('${snapshot.data}')
[Instance of 'DashBoardBanner', Instance of 'DashBoardBanner', Instance of 'DashBoardBanner']
Builder
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<List<DashBoardBanner>> futureBanner;
#override
void initState() {
super.initState();
futureBanner = getBannerDataFromServer();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ListView(
children: [
Card(
child: FutureBuilder(
future: getBannerDataFromServer(),
builder: (context,snapshot){
if(snapshot.connectionState == ConnectionState.done){
if (snapshot.hasData) {
return Text('${snapshot.data}');
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
}
return const CircularProgressIndicator();
},
),
)
],
)),
);
}
}
Class and postreq
class DashBoardBanner {
final String MsgId;
final String MsgKey;
final String MsgPic;
const DashBoardBanner(
{required this.MsgId, required this.MsgKey, required this.MsgPic});
factory DashBoardBanner.fromJson(Map<String, dynamic> json) {
return DashBoardBanner(
MsgId: json['MsgId'] as String,
MsgKey: json['MsgKey'] as String,
MsgPic: json['MsgPic'] as String,
);
}
}
Future<List<DashBoardBanner>> getBannerDataFromServer() async {
final queryParameters = {
"ApiFunc": 'Banner',
"UserKey": getDeviceKey(),
"Token": getDeviceToken(),
"SubmitContent": json.encode({"MobileNo": getMobileNo1()})
};
final response = await http.post(
Uri.http('somesite.net', '/capi.aspx', queryParameters),
);
if (response.statusCode == 200) {
Map<String, dynamic> data = jsonDecode(response.body);
final splitoff = jsonEncode(data['RespContent']);
return compute(parseBanner, splitoff);
} else {
throw Exception('Failed to load Data');
}
}
List<DashBoardBanner> parseBanner(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed
.map<DashBoardBanner>((json) => DashBoardBanner.fromJson(json))
.toList();
}
Edit : i rebuilt the file replicating reference[1] and it finally displayed the data i needed, it seems the issue stem from not having this 2nd widget which return the obj back , however how do i combine the 2nd build widget into the first without needing the whole widget as having a whole build widget to return 1 line seems pointless?
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body:Container(
child: FutureBuilder<List<DashBoardBanner>>(
future: getBannerDataFromServer(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text('An error has occurred!'),
);
} else if (snapshot.hasData) {
print(snapshot.data!.length);
return DashBoardBannersList(dashboardBanners: snapshot.data!); <--- original issue due to not having this
} else {
return CircularProgressIndicator();
}
},
),
),
);
}
}
class DashBoardBannersList extends StatelessWidget {
const DashBoardBannersList({Key? key, required this.dashboardBanners}) : super(key: key);
final List<DashBoardBanner> dashboardBanners;
#override
Widget build(BuildContext context) {
return Text(dashboardBanners[0].MsgId);
}
}
This error is caused because of the sound null safety
snapshot.data might be null for some requests so you can't access the array at a certain index cause it can be null.
If you know for sure snapshot.data exists you can use the ! operator to tell dart the variable is not null for sure like that:
snapshot.data![index];
You can also check if the data is null before accessing it like that:
if (snapshot.data != null) {
// do something with snapshot.data[index]
}
I recommed to read more about sound null safety here
Check the Firestore docs.
Inside snapshot.data, there's docs (every document of your collection).
The code is from there:
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
return ListTile(
title: Text(data['full_name']),
subtitle: Text(data['company']),
);
}).toList(),
);
},
);
}
The code above shows how to convert every doc (type DocumentSnapshot) to a JSON format (that can be represented with Map<String, dynamic>). To access to the doc id, you'll access with document.id, because it isn't inside the document.data() method.
You wanna retrieve a list of DashBoardBanner but you forget initialize the futurebuilder by adding a ListView.builder().
Try to use the following code idea :
FutureBuilder(
future: getBannerDataFromServer(http.Client()),
builder: (context, AsyncSnapshot snapshot) {
print(snapshot.hasData);
if (snapshot.hasError) {
return CircularProgressIndicator();
} else if (snapshot.hasData) {
return Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
var data = snapshot.data![index];
return DashBoardBannersList(dashboardBanners: data);
},),
),},
},)