How do I generate a list of widgets from firebase firestore database? - firebase

I'm trying to figure out how to iterate through documents in firestore and create a text widget for each one.
I've figured out how to access those elements. I used debugPrint() and got the results I'm expecting, but I can't get it to display below my other widgets. I get a red screen with a ton of errors (on phone).Below is my code for what I've tried so far.
QuerySnapshot querySnapshot = await
Firestore.instance.collection("users").document(user.uid).collection("trails").getDocuments();
var list = querySnapshot.documents;
list.forEach((doc) => debugPrint(doc.data["Trail Name"].toString()));//works
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
//these widgets are generating correctly
Text(
"First Name: $firstName",
style: TextStyle(color: Colors.white, ),
),
Text(
"Last Name: $lastName",
textAlign: TextAlign.left,
style: TextStyle(color: Colors.white,),
),
Text(
"Email: $email",
style: TextStyle(color: Colors.white, ),
),
//these ones are causing my errors.
list.forEach((doc) => Text(
"Trail Name: ${doc.data["Trail Name"].toString()}",
style: TextStyle(color: Colors.white, ),
),)
],
);
final topContent = Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.40,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
child: Center(
child: topContentText,
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
return Scaffold(
body: Column(
children: <Widget>[topContent, bottomContent],
),
);
The screen on my device lights up red with errors on creating child widgets, when I'm expecting it to display the Trail Name(s) below the other info. I only included necessary code, but could include more (such as the widget's build method) if needed. Thanks for any assistance. I'm new to flutter.

Try using the map function:
List<Widget> _widgets = list.map((doc) => Text(
"Trail Name: ${doc.data["Trail Name"].toString()}",
style: TextStyle(color: Colors.white, ),
),).toList();
And then for the children of the column, just add that list to the list you specify, like:
children: [ ... ] + _widgets;

Related

How to navigate to a specific route in a list full of the same widget?

I have a an app which the user is able to add in books and it upload to the firestore database, and then I use a streamBuilder() to recieve all the data and display it in a list of GestureDetector() with the card() as a child.
Here is the code for the
final bookWidget = GestureDetector(
key: ValueKey(loggedInUser.email),
onTap: () {
print(title);
},
child: Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: 100,
height: 140,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(bookCoverURL)),
),
),
Container(
width: 230,
//color: Colors.red,
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Text(
category.toString(),
style: TextStyle(
color: Colors.grey,
fontStyle: FontStyle.italic,
),
),
Container(
margin: EdgeInsets.only(top: 10),
child: Text(
title.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 17,
),
),
),
Container(
margin: EdgeInsets.only(top: 10),
child: Text(
(author),
style:
TextStyle(color: Colors.grey),
),
),
],
),
),
Icon(
Icons.arrow_forward_ios,
color: Colors.black,
size: 15,
)
],
),
],
),
//color: Colors.yellowAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 5,
margin: EdgeInsets.all(10),
),
);
bookWidgets.add(bookWidget);
And then I display all my code in the screen by :
Column(
children: bookWidgets,
)
But how can I make the app navigate to a new screen when the user pressed on a specific card()? Since all of them are the same widget and have no unique identifier?
Any help is greatly appreciated! Thank you!
GestureDetector(
key: ValueKey(loggedInUser.email),
onTap: () {
Navigator.pushNamed(
context,
'/routeNameHere',
arguments: id,
);
},
)
In parameter arguments: ID - you can change the id by the id of the card that you want to navigate to.
You must create a page for the display detail of the card, which just displays a card with same id in the argument. So on your new page, create a variable for receiving the argument, e.g.:
final cardId = ModalRoute.of(context).settings.arguments as String;
So the page can display the card depending on the cardId.
You will need to create an identifier to pass (in this case “book”). In Flutter, these are necessary when calling or passing an object.
However, in regards to using Named Routes , this can allow you to send the data without the identifier but is considered bad practice in coding as you would not have a reference to the call or be able to back trace through the data.
Keeping the above in mind, it is possible to use the OnTap() inside each child card container so that on handle clicks or tap gestures, the user is taken to a different screen using routes as it is part of the GestureDetector class.

Fetch user data from firestore and show them in profile screen using flutter

The issue here is that when I fetch the data, I am suppose to fetch it for the current user but it is rather fetching data for all users within that collection.
I have done reading and watched a number of videos for a possible solution but I can't seem to find how to do this. Your help is needed please. Thanks.
A excerpt of the bode is below.
File image;
TextEditingController loginNameController = TextEditingController();
TextEditingController loginPhoneController = TextEditingController();
TextEditingController loginAddressController = TextEditingController();
clearForm() {
setState(() {
image = null;
loginNameController.clear();
loginPhoneController.clear();
loginAddressController.clear();
});
}
//=====> FOR INSTANCES OF FIREBASE <=====
final auth = FirebaseAuth.instance;
final db = FirebaseFirestore.instance;
User user = FirebaseAuth.instance.currentUser;
body: Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: StreamBuilder(
stream: db.collection("collection name").snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot){
if (!snapshot.hasData) {
return Center(
child: spinkit,
);
}
return ListView.builder (
itemCount: snapshot.data.docs.length,
itemBuilder: (BuildContext context, int index){
return Stack(
children: [
Column(
children: [
Stack(
children: [
// ===> RETRIEVING USER DETAILS AND SHOWING IT IN A ROW <===
Container(
padding : EdgeInsets.only(top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CircleAvatar(
backgroundColor: Palette.mainColor,
radius: 50,
child: ClipOval(
child: SizedBox(
height: 150,
width: 150,
child: image == null ? Center(
// child: Image.asset("asset/images/placeholder.png", fit: BoxFit.cover,),
child: Image.network(snapshot.data.documents[index].get("image")),
):
Image.file(image, fit: BoxFit.cover,),
),
),
),
SizedBox(width: 16,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 0),
child: Text(snapshot.data.documents[index].get("Name"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),),
),
SizedBox(height: 5,),
Text(snapshot.data.documents[index].get("Address"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black54,
fontSize: 16,
),),
SizedBox(height: 5,),
Text(snapshot.data.documents[index].get("Number"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black54,
fontSize: 16,
),),
],
),
),
Padding(
padding: EdgeInsets.only(left: 0, bottom: 15),
child: IconButton(
icon:Icon(Icons.edit, color: Palette.mainColor, ),
onPressed: () { },
),
),
],
),
),
],
),
],
),
],
);
},
);
},
),
)
The collection name is members
Try like this, stream of your widget should be like this, as said above.
db.collection("Users").document(user.uid).snapshots();
for length in Listview.builder, change it too
snapshot.data.length;
And last, All the data which you fetch data like this should change into
from:
snapshot.data.documents[index].get("image")
To:
snapshot.data["image"]
Note I didn't test it. So, it might or might not work.
First of All use a DocumentSnapshot Shown below:
StreamBuilder<DocumentSnapshot>
Make a collection to get current user Profile data.
db.collection("Users").doc(user.uid).snapshots();
Remove ListView.builder
To get an Email Address use the below Line
Text('${streamSnapshot.data['Email Address']}'),
Here is the complete Article https://medium.com/#kamranktk807/fetch-user-data-from-firestore-and-show-them-in-profile-screen-using-flutter-609d2533e703
By the way I sol this problem with the help of a Professional Flutter Developer SHAKIR ZAHID [shakirzahid191#gmail.com].

flutter :sharedpreference retrieving null value [duplicate]

This question already has answers here:
What is a NoSuchMethod error and how do I fix it?
(2 answers)
Closed 2 years ago.
The method 'getStringList' was called on null.
Receiver: null
Tried calling: getStringList("userCart")
The relevant error-causing widget was:
Consumer .the details are stored in firebase,the error occurs when displaying the no of items the user have added to the cart.
the CartItemCounter dart file is that thrown error when calling consumer.initially useCart is given as garbage value when registering in firebase.
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
class StoreHome extends StatefulWidget {
#override
_StoreHomeState createState() => _StoreHomeState();
}
class _StoreHomeState extends State<StoreHome> {
SharedPreferences sharedPreferences;
#override
void initState() {
super.initState();
SharedPreferences.getInstance().then((prefs){
setState(() {
sharedPreferences=prefs;
});
});
}
#override
Widget build(BuildContext context) {
final _width=MediaQuery.of(context).size.width;
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("E_shop",style: TextStyle(color:Colors.red,),
),
centerTitle: true,
actions: [
Stack(
children: [
IconButton(icon:Icon(Icons.add_shopping_cart,color: Colors.grey,),
onPressed: (){
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>StoreHome()));
},
),
Positioned(child: Stack(
children: [
Icon(Icons.brightness_1,size: 20.0,
color: Colors.green,),
Positioned(
top: 3.0,
bottom: 4.0,
left:4.0,
child: Consumer<CartItemCounter>(
builder: (context, counter,_){
return Text(
counter.count.toString(),
style:TextStyle(color:Colors.white,fontSize:12.0,fontWeight:FontWeight.w500),
);
},),
),
],
),
),
],
),
],
),
drawer: MyDrawer(),
body: CustomScrollView(
slivers: [
SliverPersistentHeader(
pinned: true,
delegate: SearchBoxDelegate(),
),
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection("items").limit(15).orderBy("publishedDate",descending: true).snapshots(),
builder: (context,dataSnapshot){
return !dataSnapshot.hasData
?SliverToBoxAdapter(child: Center(child: circularProgress(),),)
:SliverStaggeredGrid.countBuilder(
crossAxisCount: 1,
itemCount: 5,
staggeredTileBuilder: (c)=>StaggeredTile.fit(1),
itemBuilder: (context,index){
ItemModel model=ItemModel.fromJson(dataSnapshot.data.docs[index].data());
return sourceInfo(model,context);
},
);
},
),
],
),
),
);
}
circularProgress(){
return Container(
alignment: Alignment.center,
padding: EdgeInsets.only(top: 12.0),
child: CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(Colors.lightGreenAccent),),
);
}
Widget sourceInfo(ItemModel model, BuildContext context , {Color background, removeCartFunction}) {
return InkWell(
onTap: (){
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>ProductPage(itemModel:model)));
},
splashColor: Colors.pink,
child: Padding(
padding: EdgeInsets.all(6.0),
child: Container(
height: 300.0,
width: MediaQuery.of(context).size.width,
child: Row(
children: [
Image.network(model.thumbnailUrl ,width:140.0,height: 140.0,),
SizedBox(width: 4.0,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.0,),
Container(
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(child: Text(
model?.title ?? '',style: TextStyle(color: Colors.black,fontSize: 14.0),
),
)
],
),
),
SizedBox(height: 5.0,),
Container(
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(child: Text(
model?.shortInfo ?? '',style: TextStyle(color: Colors.black54,fontSize: 12.0),
),
)
],
),
),
SizedBox(height: 20.0,),
Row(
children: [
Container(
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.pink,
),
alignment: Alignment.topLeft,
width: 40.0,
height: 43.0,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"50%",style: TextStyle(
fontSize: 15.0,color: Colors.white,
fontWeight: FontWeight.bold,
),
),
Text(
"OFF",style: TextStyle(
fontSize: 12.0,color: Colors.white,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
SizedBox(width: 10.0,),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(top: 0.0),
child: Row(
children: [
Text(
"Original Price :%",
style: TextStyle(
fontSize: 14.0,
color: Colors.grey
),
),
Text(
(model?.price??'').toString(),
style: TextStyle(
fontSize: 15.0,
color: Colors.grey,
decoration: TextDecoration.lineThrough,
),
)
],
),
),
Padding(
padding: EdgeInsets.only(top: 5.0),
child: Row(
children: [
Text(
"New Price :%",
style: TextStyle(
fontSize: 16.0,
color: Colors.red,
),
),
Text(
"%",
style: TextStyle(
fontSize: 15.0,
color: Colors.grey,
),
),
Text(
(model.price+model.price).toString(),
style: TextStyle(
fontSize: 15.0,
color: Colors.grey
),
),
],
),
),
],
),
],
),
Flexible(child: Container(
),
),
//to implement cart add/remove remove
Align(
alignment: Alignment.centerRight,
child: removeCartFunction==null
?IconButton(
icon: Icon(Icons.add_shopping_cart,color: Colors.pinkAccent,),
onPressed: (){
checkItemInCart(model.shortInfo,context);
},)
:IconButton(
icon: Icon(Icons.delete),
onPressed: null)
)
],
))
],
),
),
),
);
}
void checkItemInCart(String shortInfoAsId, BuildContext context) {
sharedPreferences.getStringList(EcommerceApp.userCartList).contains(shortInfoAsId)
?Fluttertoast.showToast(msg: "item already in cart")
:addItemToCart(shortInfoAsId,context);
}
addItemToCart(String shortInfoAsId, BuildContext context) {
List tempCartList=sharedPreferences.getStringList(EcommerceApp.userCartList);
tempCartList.add(shortInfoAsId);
FirebaseFirestore.instance.collection("users").doc(sharedPreferences.getString(EcommerceApp.userUID))
.update({
EcommerceApp.userCartList: tempCartList,
}).then((value){
Fluttertoast.showToast(msg: "Item added to cart successfully");
sharedPreferences.setStringList(EcommerceApp.userCartList, tempCartList);
Provider.of<CartItemCounter>(context,listen: false).displayResult();
});
}
}```
the CartItemCounter dart file is that thrown error when calling consumer<cartitemcounter>.initially useCart is given as garbage value when registering in firebase.
```class CartItemCounter extends ChangeNotifier{
static SharedPreferences sharedPreferences;
int _counter=sharedPreferences.getStringList("userCart").length-1;
int get count=>_counter;
Future<void> displayResult() async{
int _counter=sharedPreferences.getStringList("userCart").length-1;
await Future.delayed(const Duration(milliseconds: 100),(){
notifyListeners();
});
}
}```
The method 'getStringList' was called on null.
Receiver: null
Tried calling: getStringList("userCart")
The relevant error-causing widget was:
Consumer<CartItemCounter> .the details are stored in firebase,the error occurs when displaying the no of items the user have added to the cart.
The error:
getStringList("...") was called on null
implies that the method was called on a null object which means that you are trying to call sharedPrefs.getStringList()
but, sharedPrefs is null at the moment as it has not been loaded yet. Hence, you encounter the problem. A simple hack to solve this problem:
#override
Widget build(BuildContext context) {
final _width=MediaQuery.of(context).size.width;
return SafeArea(
child:
sharedPrefs == null? // If sharedPrefs is not retreived yet
Scaffold(body: Center(child: Text("Hold on :)"))): // Show this widget
Scaffold( // Else do your normal job
appBar: AppBar(
title: Text("E_shop",style: TextStyle(color:Colors.red,),
),
......... and so on..

How can I get a subcollection on Firebase without specifying it?

Hey Guys I have these subcollections on my Firebase database under the "vocabulary" collection, but I would need to call them without specifying it, as they are more than one and they are called from the same page. Instead of the collection "colors", is it possible to not specify it as the "documentID" but for the collection?
class CategoryScreen extends StatelessWidget {
final DocumentSnapshot vocabulary;
CategoryScreen(this.vocabulary);
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<QuerySnapshot>(
future: Firestore.instance.collection('vocabulary').document(vocabulary.documentID)
.collection('colors').getDocuments(),
builder: (context, snapshot){
if(!snapshot.hasData)
return Center(
child: CircularProgressIndicator(),);
else
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: Card(
elevation: 7.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50)
),
child: Column(
children: <Widget>[
Container(
height: 350.0,
width: 350.0,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(vocabulary.data["image"]
),
fit: BoxFit.fill),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(50),
topRight: Radius.circular(50)))
),
Container(
height: 70.0,
width: 300.0,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Center(
child: AutoSizeText(vocabulary.data["name"],
style: TextStyle(
fontFamily: 'Twiddlestix',
fontSize: 25,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
minFontSize: 15,
),
)
),
),
],
),
),
),
],
);
},
),
);
}
}
There are no wildcards in Cloud Firestore references to documents. So in order to create a query, you need to know all collection names. If you need to get only some documents within a collection based on a specific property, you'll have to do a query using some field value as a filter.
Instead of the collection "colors", is it possible to not specify it as the "documentID" but for the collection?
No, it's not possible. You cannot substitute that.

How to make changes at the particular index of a list whose data is fetched from cloud Firestore in flutter?

In my flutter application, i fetched my data in a list from Firestore and now want to an ADD or REMOVE option for increasing or decreasing the number of units of that particular item on the list but after several tries not able to do that as the count on the entire list gets updated not that particular element in that index. Can anyone help me in this
CustomScrollView(
physics: BouncingScrollPhysics(),
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate((context, index){
return Container(
margin: EdgeInsets.only(top: 15.0,left: 15.0,right: 15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
child: Text(snapshot.data.documents[index].documentID,style: TextStyle(fontFamily: "DelishN", fontSize: 15.0),),
),
Container(
decoration: BoxDecoration(
border: Border.all(
width: 2.0,
color: Colors.black
),
borderRadius: BorderRadius.circular(23.0)
),
child: Row(
children: <Widget>[
FloatingActionButton(
onPressed: (){
add();
},
mini: true,
child: Icon(Icons.add, color: Colors.black,),
backgroundColor: Colors.white,
),
SizedBox(
width: 7.0,
),
Text(_n.toString(), style: TextStyle(fontFamily: 'DelishN',),),
SizedBox(
width: 7.0,
),
FloatingActionButton(
onPressed: (){
minus();
},
mini: true,
child: Icon(Icons.remove, color: Colors.black,),
backgroundColor: Colors.white,)
],
),
)
],
)
);
},
childCount: snapshot.data.documents.length))],
)

Resources