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





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















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),),
);
}









share|improve this question























  • Can't you just call navigator pop on a callback from the data save, eg addShoppingListItemsToDB (or make that synchronous) IF it's a requirement that you shouldn't be able to go back until it's saved ?

    – Ian
    Jan 4 at 14:53


















0















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),),
);
}









share|improve this question























  • Can't you just call navigator pop on a callback from the data save, eg addShoppingListItemsToDB (or make that synchronous) IF it's a requirement that you shouldn't be able to go back until it's saved ?

    – Ian
    Jan 4 at 14:53














0












0








0








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),),
);
}









share|improve this question














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),),
);
}






dart flutter sqflite






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 4 at 14:37









Rakesh KRakesh K

3,070133749




3,070133749













  • Can't you just call navigator pop on a callback from the data save, eg addShoppingListItemsToDB (or make that synchronous) IF it's a requirement that you shouldn't be able to go back until it's saved ?

    – Ian
    Jan 4 at 14:53



















  • Can't you just call navigator pop on a callback from the data save, eg addShoppingListItemsToDB (or make that synchronous) IF it's a requirement that you shouldn't be able to go back until it's saved ?

    – Ian
    Jan 4 at 14:53

















Can't you just call navigator pop on a callback from the data save, eg addShoppingListItemsToDB (or make that synchronous) IF it's a requirement that you shouldn't be able to go back until it's saved ?

– Ian
Jan 4 at 14:53





Can't you just call navigator pop on a callback from the data save, eg addShoppingListItemsToDB (or make that synchronous) IF it's a requirement that you shouldn't be able to go back until it's saved ?

– Ian
Jan 4 at 14:53












1 Answer
1






active

oldest

votes


















0














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),),





share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54041012%2fhow-to-update-page-state-after-navigator-pop-from-an-alert-box%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    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),),





    share|improve this answer




























      0














      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),),





      share|improve this answer


























        0












        0








        0







        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),),





        share|improve this answer













        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),),






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jan 4 at 14:53









        diegoveloperdiegoveloper

        15.7k12636




        15.7k12636
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54041012%2fhow-to-update-page-state-after-navigator-pop-from-an-alert-box%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Angular Downloading a file using contenturl with Basic Authentication

            Olmecas

            Can't read property showImagePicker of undefined in react native iOS