Reputation: 195
Im trying to retrieve a list of monthly expenses from Firebase, add up the amount of each monthly expense and show it in a FutureBuilder. In the Text widget i'm simply getting null. Been trying to google an answer for the past half hour but i don't even know where to begin as in what to search for.
Tried throwing in some print statement to see whats going on but any print statement I put in after the provider call doesn't show.
EDIT: Added Future casts to the commented lines. still no luck. but ignored the variable and called the future function directly from the FutureBuilder. Now all print statements are working and it is returning an instance of 'MonthlyExpense'. It is null still.
class SummaryView extends StatefulWidget {
@override
_SummaryViewState createState() => _SummaryViewState();
}
class _SummaryViewState extends State<SummaryView> {
/* Removed future variable and initState()
Future<double> _totalExpensesAmount; //Future<double> added
@override
void initState() {
super.initState();
print("init");
_totalExpensesAmount = _getTotalExpensesAmount();
}
*/
Future<double> _getTotalExpensesAmount() async { //Future<double> added
print("started");
final user = Provider.of<BPUser>(context);
print("user: $user");
double expensesTotal = 0.0;
var snapshot = await FirebaseFirestore.instance
.collection("BPUsers/${user.uid}/monthlyexpenses")
.get();
print(snapshot);
List<MonthlyExpense> searchedProducts =
DatabaseService().monthlyExpenseListFromSnapshot(snapshot);
print(searchedProducts);
for (var i = searchedProducts.length; i >= 1; i--) {
expensesTotal += double.parse(searchedProducts[i].amount);
}
return Future<double>expensesTotal; //Future<double> added
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: mainBackgroundColor,
body: Column(
children: [
Container(
child: FutureBuilder(
future: _getTotalExpensesAmount(), // called the function directly
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(
"${snapshot.data}",
style: nameStyle,
);
} else {
return Text("Loading...");
}
}),
)
],
),
);
}
}
The monthlyExpenseListFromSnapshot function (which works perfectly in another widget I use it in):
List<MonthlyExpense> monthlyExpenseListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((doc) {
return MonthlyExpense(
name: doc.data()['name'] ?? '',
amount: doc.data()['amount'] ?? '',
isActive: doc.data()['isActive']);
}).toList();
}
Upvotes: 0
Views: 121
Reputation: 195
First issue was to skip the variable and the init call and call the _getTotalExpensesAmount() future function (adding the Future signature to it).
Secondly my for loop was wrong. needed to change the conditions to:
for (var i = searchedProducts.length - 1; i >= 0; i--) {
Everything is working fine now!
Upvotes: 1
Reputation: 1872
You need to define the signature of the function to represent what it is expected, in this case Future <double>
.
// ....
Future<double> _getTotalExpensesAmount() async {
Upvotes: 1
Reputation: 671
You're getExpensesTotal doesn't return a future. Because of this, the widgetvwill never rebuild since the data is already calculated. FutureBuilder and StreamBuilder only cause a rebuild AFTER data been loaded after the initial build. Try surrounding your expensesTotal with Future.value.
Upvotes: 1