Fetching particular data from firestore using Flutter - flutter

I am using Firestore as a database with my Flutter Application. I am storing data in the following way:
I want to get data of shop based upon document ID(which is the id of currently logged in user). I am using following code but unable to fetch particular data.
And using stream builder for to display data.
StreamBuilder(
stream: Firestore.instance
.collection('Shops')
.document(user.uid)
.snapshots(),
builder: (context, snapshot) {
print(snapshot.hasData);
if (snapshot.hasData) {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, i) {
return SingleChildScrollView(
child: Column(children: <Widget>[
_buildRow(context, snapshot, i),
SizedBox(
height: 20,
),
_buildShopDetails(context, snapshot, i),
_buildReviewsRatingCard(snapshot, i),
]),
);
});
} else {
return CircularProgressIndicator();
}
},
),
So kindly help me in solving my problem.

Related

How to listen to stream and update Flutter GridView builder accessing Firebase

I need an example code in which a Flutter Gridview builder streams Firebase data (for example with a single Collection and multiple Documents with multiple fields in each) that can be modified by the user straight from the Gridview
I've watched this tutorial => https://www.youtube.com/watch?v=ErP_xomHKTw
Although it shows how to access and modify data from Firebase I still can't wrap my head around the Firebase and Gridview builder interaction.
Stream Builder using GridView
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('products').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 3 / 2,
crossAxisSpacing: 20,
mainAxisSpacing: 20),
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return Column(
children:[
Text(doc['name']),
Text(doc['price']);
);
);
}),
} else {
return Text("No data");
}
},
)
Stream Builder using ListView
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('products').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return Column(
children:[
Text(doc['name']),
Text(doc['price']);
);
});
} else {
return Text("No data");
}
},
)

after running the code why its given "Bad state: field does not exist within the DocumentSnapshotPlatform" and the apps screen is red?

I tried to retrieve two collections of data from firebase to screen as a list in Flutter app.But it shows error "Bad state: field does not exist within the DocumentSnapshotPlatform". I don't know how to fix it. Can anyone help me how to solve it? Thank you!!
here is my code
final CollectionReference _addExpense= FirebaseFirestore.instance.collection('add_expense');
final CollectionReference _addincome= FirebaseFirestore.instance.collection('add_income');
i tried it for two collection tables to retrieve the data.
Expanded(
flex: 4,
child: StreamBuilder(
stream: _addExpense.snapshots(),
builder: (context, snapshot1) {
return StreamBuilder(
stream: _addincome.snapshots(),
builder: (context, snapshot2) {
if (!snapshot2.hasData) return const Text('Loading...');
if (!snapshot1.hasData) return const Text('Loading...');
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: ScrollPhysics(),
// itemExtent: 550.0,
itemCount: snapshot2.data!.docs.length,
itemBuilder: (BuildContext context, index) {
final DocumentSnapshot documentSnapshot = snapshot2.data!.docs[index];
final DocumentSnapshot documentSnapshot1 = snapshot1.data!.docs[index];
return Column(
Card(
child: ListTile(
subtitle: Row(
children: <Widget>[
Container(
width: 75,
child: Text(
"${documentSnapshot.get('dates')}"//['dates']}"
"\n${documentSnapshot.get('times')}"//['times']}"
"\n${documentSnapshot.get('payment')}"//['payment']}"
"\n${documentSnapshot.get('notes')}"//['notes']}"
),
),
This occurs when the document you're trying to read doesn't contain all the fields you are trying to read.

how to add return two widgets using future builder

I want to display two widgets, like a text and after it a table, both contains data from api. i am using stack for it, i created a separate method for table. here is the code
Container(
padding: EdgeInsets.fromLTRB(15, 470, 0, 0),
child:SingleChildScrollView(
scrollDirection: Axis.vertical,
child: FutureBuilder(
future: _getRecord(),
builder: (BuildContext context, AsyncSnapshot<List<History>> snapshot) {
// Check if the data has been received.
if (snapshot.hasData) {
// Return the widget and provide the received data.
if(historyList.length!=0){
return Stack(children:<Widget>[
Expanded(
child: ListView.builder(
itemCount: snapshot.data.length,
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(subtitle:Text(snapshot.data[index].date));})),// it is not displaying this line
SizedBox(height: 30,),
attendanceHistory(snapshot.data)
]);
// return attendanceHistory(snapshot.data);
}
}
attendanceHistory(snapshot.data) this line display the table with data, but subtitle is not working
kindly please help how to do this

Flutter Streambuilder is duplicating items

I have a StreamBuilder connected to a List and the List gets its data from Firebase, but every there is an Event in my Database the items in my Streambuilder get Duplicated.
Here is my StreamBuilder code:
StreamBuilder(
stream: masterListStart().asStream(),
builder: (context, snapshot) {
//return coursesList.length == 0
return finishedLoadingList
? ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: storysList.length,
itemBuilder: (context, index) {
//
StoryItems data = storysList[index];
//
return StoryItems(
data: data,
);
},
)
: CircularProgressIndicator();
},
),
How I can prevent the StreamBuilder from doing this?
Instead of using finishedLoadingList, you can simply check your snapshot connectionState as following
StreamBuilder(
stream: masterListStart().asStream(),
builder: (context, snapshot) {
//return coursesList.length == 0
return (ConnectionState.done == snapshot.connectionState) ? ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: storysList.length,
itemBuilder: (context, index) {
//
StoryItems data = storysList[index];
//
return StoryItems(
data: data,
);
},
) : CircularProgressIndicator();
},
),

Having a different StreamBuilder for every tab in TabBarView

I am trying to create a home page that has 3 tabs: Friends, Groups and Events.
After finally managing to load events for the current user only, I realised ill have a hard time loading different data for each tab - as the StreamBuilder stream: will always be the same for all the tabs.
I need help finding a way to have a different StreamBuilder for each of my tabs.
Code below:
StreamBuilder(
stream: _streamer(),//Firestore.instance.collection("Events").snapshots(),
builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
if (!snapshot.hasData) return const Text("Loading...");
return new SizedBox(
height: MediaQuery.of(context).size.height - 42 - MediaQuery.of(context).padding.bottom -AppBar().preferredSize.height - kToolbarHeight,
child: Column(
children: <Widget>[
Expanded(
child: TabBarView(
controller: _tabController,
children: <Widget>[
Container(
child: ListView.separated(
itemCount: snapshot.data.length,
itemBuilder: (context, index) =>
_buildListItem(context,
snapshot.data[index]),
separatorBuilder: (context, index) {
return Divider();
},
shrinkWrap: true,
),
),
Container(
child: ListView.separated(
itemCount: snapshot.data.length,
itemBuilder: (context, index) =>
_buildListItem(context,
snapshot.data[index]),
separatorBuilder: (context, index) {
return Divider();
},
shrinkWrap: true,
),
),
Container(
child: ListView.separated(
itemCount: snapshot.data.length,
itemBuilder: (context, index) =>
_buildListItem(context,
snapshot.data[index]),
separatorBuilder: (context, index) {
return Divider();
},
shrinkWrap: true,
),
),
],
),
)
],
));
},
)
This is how the home page looks
I assume you're loading all data required for all your tabs using that stream. What you could do is have distinct pairs of stream/StreamBuilder for each tab:
... // widgets leading up to the TabBarView
TabBarView(
controller: _controller,
children: <Widget>[
StreamBuilder(
stream: friendsStream,
builder: (BuildContext context, AsyncSnapshot<SomeData> snapshot) {
return FriendsWidget();
}
),
StreamBuilder(
stream: groupsStream,
builder: (BuildContext context, AsyncSnapshot<SomeData> snapshot) {
return GroupsWidget();
}
),
//... etc
]
)
You could also wrap ONLY the widgets that should be rebuilt with a StreamBuilder instead of wrapping the whole parent widget:
... // widgets leading up to the TabBarView
TabBarView(
controller: _controller,
children: <Widget>[
Column(
children: <Widget>[
SomeWidget(),
AnotherWidget(),
StreamBuilder(
stream: friendsStream,
builder: (BuildContext context, AsyncSnapshot<SomeData> snapshot) {
return FriendsWidget();
}
)
]
),
// ... etc
]
)
If you are compelled to load all your data from the database at once, you could use a Repository class to load and store all your data, and then, depending on your architecture, have streams built from that class.
As a side note, I highly recommend using a Bloc with BlocBuilder. Blocs are just far superior to other designs (in most cases). flutter_bloc is my favorite.