Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to update page state after Navigator.pop() from an alert box

I have 2 pages in my Flutter app - ShoppingListsPage and ItemsListPage. I have a FloatingActionButton in ShoppingListsPage clicking which will take the user to ItemsListPage where he can add items from a ListView to a shopping list and then save the list by clicking a button in the AppBar. Once the user clicks the Done button in the AppBar, I display an AlertDialog dialog box to ask the user for a name for the list. Once the user enters the list name and clicks Save button in the dialog, I save the list details in an SQLite database(I'm using sqflite plugin for database interaction) and then want to move the user back to ShoppingListsPage where the newly created list has to be displayed.

Given this context, What I observe is that when I save the list to the database and navigate to ShoppingListsPage using Navigate.pop(context), the code to fetch the shopping lists from the database is executed but it does not retrieve the latest addition and hence the ListView in ShoppingListsPage is not updated with the latest changes. However, if I navigate to some other page and come back, the newly added list is displayed. It looks like the fetch from the database in ShoppingListsPage is happening before the data is persisted in the database. How do I make sure that the fetch is successful(with the latest data) from the database?

On a related note, what is a better way to make sure that the async function I have to save the data to the database is called and completed before Navigator.pop(context) takes the user to the previous screen? All my functions to interact with the SQLite database are async functions.

Here's the code to display the dialog in ItemsList page, save the data and navigate back to ShoppingListsPage:

_showListNameDialog() async {
    final textController = new TextEditingController();
    String retVal = await showDialog<String>(
        context: context,
        child: AlertDialog(
          contentPadding: EdgeInsets.all(12.0),
          content: Row(
            children: <Widget>[
              Expanded(
                child: TextField(
                  decoration: InputDecoration(
                      labelText: 'List Name',
                      hintText: 'Monthly groceries'
                  ),
                  controller: textController,
                ),
              )
            ],
          ),
          actions: <Widget>[
            FlatButton(
                onPressed: (){
                  Navigator.pop(context);
                },
                child: Text('Cancel')
            ),
            FlatButton(
                onPressed: (){
                  addShoppingListItemsToDB(textController.text, shoppingListItemMap);
                  Navigator.pop(context, textController.text);
                },
                child: Text('Save')
            )
          ],
        )
    );
    Navigator.pop(context);
    setState(() {
    });
  }

Here's the code in ShoppingListsPage to fetch and display the data:

Future<List<ShoppingList>> getShoppingLists() async {
  DBHelper dbClient = DBHelper();
  return dbClient.getShoppingLists();
}

@override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('Shopping Lists'),
      ),
      body: Container(
        padding: EdgeInsets.all(12.0),
        child: FutureBuilder<List<ShoppingList>>(
            future: getShoppingLists(),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return ListView.builder(
                    itemCount: snapshot.data.length,
                    itemBuilder: (context, index) {
                      String listName = snapshot.data[index].listName;
                      return Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            ListTile(
                              leading: CircleAvatar(
                                child: Text(listName==''?'u':listName[0]),
                              ),
                              title: Text(snapshot.data[index].listName, style: TextStyle(fontSize: 18.0),),
                              subtitle: Text('Created at ${snapshot.data[index].createdAt}', style: TextStyle(color: Colors.grey),),
                              onTap: () {
                                Navigator.push(
                                    context,
                                    MaterialPageRoute(builder: (context) => ShoppingListItemsPage(list_name: snapshot.data[index].listName,))
                                );
                              },
                            ),
                            Divider()
                          ]
                      );
                    }
                );
              } else if (snapshot.hasError) {
                return Text('Error: ${snapshot.error}');
              }
              return Container(alignment: AlignmentDirectional.center, child: CircularProgressIndicator(),);
            }
        ),
      ),
      floatingActionButton: FloatingActionButton(
          onPressed: (){
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => ItemListPage(listName: 'Untitled',listItems: null,)));
          },
      child: Icon(Icons.add),),
    );
  }
like image 830
Rakesh K Avatar asked Jan 04 '19 14:01

Rakesh K


1 Answers

You could use await keyword to wait until the user pop the Widget.

         floatingActionButton: FloatingActionButton(
                  onPressed: () async {
                    await Navigator.of(context).push(MaterialPageRoute(builder: (context) => ItemListPage(listName: 'Untitled',listItems: null,)));
                    setState(() {});
                  },
              child: Icon(Icons.add),),
like image 118
diegoveloper Avatar answered Oct 13 '22 06:10

diegoveloper