Reputation: 35
This is my first time asking a question because I've tried everything that I've researched from this website for hours but nothing seems to work. I'm trying to get the total price of my cart but every time the state changes it constantly adds and I just want the total to stay as it is when I'm changing pages. Even clicking a delete button from my cart page, refreshes the function and it adds another value to the total. Thank you so much if someone could help me
Here's the code that I've tried
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: white,
body: StreamBuilder(
stream: FirebaseFirestore.instance
.collection("users")
.doc(user.uid)
.collection("cart")
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
FirebaseFirestore.instance
.collection("users")
.doc(user.uid)
.collection("cart")
.get()
.then((querySnapshot) {
querySnapshot.docs.forEach((result) {
total += result.data()['price'];
});
});
Upvotes: 2
Views: 988
Reputation: 2835
The problem is that total value keeps on increasing whenever stream builder is called. Also, you do not need to listen to stream and still call get(). The stream returns similar value to the get.
Change your code to this
return Scaffold(
body: StreamBuilder(
stream: FirebaseFirestore.instance
.collection("users")
.doc(user.uid)
.collection("cart")
.snapshots(),
builder: (BuildContext context, snapshot) {
if (snapshot.hasError) return Text('Something went wrong');
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
// NB: I set the value of total = 0; so that anytime the stream
// builder is called, total starts from 0.
total = 0;
snapshot.data.docs.forEach((result) {
total += result.data()['price'];
});
print(total);
print('done');
return Text('done');
},
),
);
On the other hand, you can still call this function using futureBuilder.
return Scaffold(
body: FutureBuilder(
future: FirebaseFirestore.instance
.collection("users")
.doc(user.uid)
.collection("cart")
.get(),
builder: (BuildContext context, snapshot) {
if (snapshot.hasError) return Text('Something went wrong');
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
total = 0;
snapshot.data.docs.forEach((result) {
total += result.data()['price'];
});
print(total);
print('done');
return Text('done');
},
),
);
The difference between stream and future builder is that future builder is only called once. Stream builder is called whenever the data changes.
Upvotes: 1
Reputation: 4666
Welcome!
First of all, you are using a StreamBuilder
and even though you provide a Stream
, you call the stream again at builder
method, you can can access the value of the Stream
through the snapshot
. Moreover, your builder returns no Widget
but just iterates through the items of the Stream
, to calculate I guess the total price. Instead, you can change the builder
method to something like this
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: white,
body: StreamBuilder(
stream: FirebaseFirestore.instance
.collection("users")
.doc(user.uid)
.collection("cart")
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
var data = snapshot.data;
var totalCartPrice = data.fold(0,(prev, element)=>prev['price']+element['price']);
return Text(totalCartPrice);
});
Instead of using fold
method you can iterate the data
and do the calculations by hand. But I find it more elegant.
There was no reason in calling setState
aswell, the StreamBuilder
fires changes if anything changes in the Firestore document.
Upvotes: 1
Reputation: 1089
First of all why do you send a request inside builder again? There is already a variable called "snapshot". You can get data with snapshot.data.docs.
Secondly, you are trying to increase total value every time without reset. If you set total variable to 0 before adding the prices probably it will solve your problem.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: white,
body: StreamBuilder(
stream: FirebaseFirestore.instance
.collection("users")
.doc(user.uid)
.collection("cart")
.snapshots(),
builder:(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if(snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else {
total = 0;
snapshot.data.docs.forEach((result) {
total += result.data()['price'];
});
return WidgetYouWantToUse();
}
}
Upvotes: 1