Flutter - How to get the value of a provider call function that requires 'await' within a variable?

218

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)
          },
    )
Share:
218
Gilbert Aligoey
Author by

Gilbert Aligoey

Updated on January 03, 2023

Comments

  • Gilbert Aligoey
    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
    Gilbert Aligoey over 2 years
    I'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
    Saddan over 2 years
    ok , I update my answer please check
  • Gilbert Aligoey
    Gilbert Aligoey over 2 years
    okay 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
    Saddan over 2 years
    What I think you can pass this budget.budgetName value to BudgetCard and try to retrieve this value from there like I did here