Flutter - How to get the value of a provider call function that requires 'await' within a variable?
Use provider
in a widget tree is not a good idea. Make a statefullWidget
Make a getter in your SpendingDatabaseHelper
like this
String? _budgetSpendingAmount;
String get budgetSpendingAmount=> _budgetSpendingAmount;
and initialize it like this _budgetSpendingAmount = currency.format(int.parse(c.trim()));
So using this getter you can access this value anywhere in widget tree
Future<void> _getSpecificSpending(String budgetName)async{
try{
await Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budgetName);
} catch(e){
print('error :$e');
}
}
and in your widget tree write something like this
child: FutureBuilder(
future : _getSpecificSpending(budget.budgetName)
builder: (ctx,snapshot){
var spendDataProv=Provider.of<SpendingDatabaseHelper>(context, listen: false);
return snapshot.connectionState==ConnectionState.waiting ?
CircularProgressIndicator() :
BudgetCard(
budgetName: budget.budgetName,
budgetSpent:spendDataProv.budgetSpendingAmount ,
maxBudget: currency.format(int.parse(budget.maxBudget)),
svgIcon: iconListBudgetCards[budget.iconValue],
color: colorSwatch[budget.colorValue],
percentage: 0.5)
},
)
Gilbert Aligoey
Updated on January 03, 2023Comments
-
Gilbert Aligoey over 1 year
I'm trying to make a budget app where each budget has its own spending history. Each of those spending histories would have a variable called 'budgetName' which I can compile and total the amount of spending by using sqflite code as below.
return await db.rawQuery("select sum(budgetSpent) as total from spending where budgetName ='" + budgetTitle + "'");
and this works if I try to use a
.then((value) {print(value);})
when calling the sqflite function and see the value of each budget's spendings in the debug console.But the problem is that I need the 'budgetTitle' when calling the function so it can compare with the spending's 'budgetName' to get the total spending amount.
So what I have right now is I try to get the spending amount like below:
child: BudgetCard( budgetName: budget.budgetName, budgetSpent: '${Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName}', maxBudget: currency.format(int.parse(budget.maxBudget)), svgIcon: iconListBudgetCards[budget.iconValue], color: colorSwatch[budget.colorValue], percentage: 0.5), ),
But it only returns
Instance of 'Future<dynamic>'
because it needs the 'await' before getting the value. But I couldn't find another way of doing this because it needs the 'budgetTitle' to be passed on.Any help, ideas, or suggestions are highly appreciated! thank you in advance.
Here is the database code:
String? budgetSpendingAmount; getSpecificSpending(budgetTitle) async { dynamic result = await SpendingDatabaseHelper.instance.getSpendingAmount(budgetTitle); String a = result.toString(); debugPrint('A: $a'); if (a == '[{total: null}]') { a = currency.format(int.parse('000'.trim())); budgetSpendingAmount = a; print(budgetSpendingAmount); } else { String? b = a.replaceAll(RegExp(r'[{\}\[\]\-]+'), ''); String c = b.substring(b.indexOf(":") + 1); budgetSpendingAmount = currency.format(int.parse(c.trim())); } notifyListeners(); } Future getSpendingAmount(String budgetTitle) async { Database db = await instance.database; return await db.rawQuery("select sum(budgetSpent) as total from spending where ='" + budgetTitle + "'"); }
Here is the full code of where I call the function to get the spending amount data:
Widget build(BuildContext context) { return FutureBuilder<List<Budget>>( future: Provider.of<BudgetDatabaseHelper>(context).getBudgets(), /// Displaying the data from the list builder: (context, snapshot) { if (!snapshot.hasData) { return const Center(); } return snapshot.data!.isEmpty ? const Flexible( child: Center( child: Padding( padding: EdgeInsets.only(bottom: 80.0), child: Text( 'You don\'t have any budget', style: kCaption, ), ))) : Flexible( child: ListView.builder( physics: const BouncingScrollPhysics(), itemCount: snapshot.data!.length, itemBuilder: (context, index) { final budget = snapshot.data![index]; return Dismissible( key: UniqueKey(), background: const Align( alignment: Alignment.centerRight, child: Padding( padding: EdgeInsets.only(bottom: 12.0, right: 24), child: Icon( IconlyLight.delete, color: cRed, size: 24, ), ), ), direction: DismissDirection.endToStart, onDismissed: (direction) { snapshot.data!.removeAt(index); Provider.of<BudgetDatabaseHelper>(context, listen: false) .removeMethod(budget.id!, budget.budgetName); }, child: GestureDetector( onTap: () => showModalBottomSheet( backgroundColor: Colors.transparent, context: context, enableDrag: true, isScrollControlled: true, builder: (context) { return DraggableScrollableSheet( snap: true, minChildSize: 0.43, maxChildSize: 0.85, initialChildSize: 0.43, snapSizes: const [0.43, 0.85], builder: (context, scrollController) { return ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(32), topRight: Radius.circular(32)), child: Container( color: cWhite, child: SingleChildScrollView( controller: scrollController, physics: const BouncingScrollPhysics(), child: BudgetDetails( id: budget.id!, budgetName: budget.budgetName, budgetSpent: 'budgetSpent', colorValue: colorSwatch[budget.colorValue], maxBudget: currency.format( int.parse(budget.maxBudget)), svgIcon: iconListBudgetDetails[ budget.iconValue], ), ), ), ); }, ); }, ), child: BudgetCard( budgetName: budget.budgetName, budgetSpent: '${Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName}', maxBudget: currency.format(int.parse(budget.maxBudget)), svgIcon: iconListBudgetCards[budget.iconValue], color: colorSwatch[budget.colorValue], percentage: 0.5), ), ); }, ), ); }, ); }
-
Gilbert Aligoey over 2 yearsI've actually tried to do it that way, but the thing is the 'budget.budgetName' only can be accessed below this code
final budget = snapshot.data![index];
where I clarify what 'budget' means. So putting the provider code outside of the build just doesn't work, -
Saddan over 2 yearsok , I update my answer please check
-
Gilbert Aligoey over 2 yearsokay after a few testing, the code actually works... but only if I got just 1 budget in my database. If I have more, the spending amount of 1 budget gets reflected in all budget cards. I'm thinking maybe it's because it's assigned to the 'budgetSpendingAmount' variable. You got any idea how to get it right?
-
Saddan over 2 yearsWhat I think you can pass this
budget.budgetName
value toBudgetCard
and try to retrieve this value from there like I did here