0

I have a Future Builder that builds a ListView.builder, The builder ListTiles are build by another widget that have an ontap function. I have figured out how to get something to run on the final widget by using the back button, but have not been able to figure out how to call something on the original widget on back button. For instance, I need to refresh the top level data when the user clicks back button and not just the data in the secondary widget which is already working.

I hope this makes sense, any help would be great.

UPDATE Here is the code. I am simplifying what I am showing because making a simple example will lose the context. Below you see that I have a FutureBuilder that returns a ListBuilder that returns a new ChatWidget. This is the top level, this Future needs to be refreshed when I click on the back button. However the onTap to trap the callback is in the ChatWidget.

new Expanded(
      child: new RefreshIndicator(
          child: new FutureBuilder<List<Map>>(
              future: chatlist,
              builder: (BuildContext context, AsyncSnapshot<List<Map>> snapshot) {
                switch (snapshot.connectionState) {
                  case ConnectionState.none: return new Text('Waiting to start');
                  case ConnectionState.waiting: return new Text('Loading...');
                  default:
                    if (snapshot.hasError) {
                      return new Text('Error: ${snapshot.error}');
                    } else {
                      return new ListView.builder(
                        itemBuilder: (context, index) {
                          ChatServerList mychat = new ChatServerList(snapshot.data[index]['msgkey'],snapshot.data[index]['refid'],snapshot.data[index]['referralname'], snapshot.data[index]['oid'],snapshot.data[index]['sendname'],snapshot.data[index]['pid'],snapshot.data[index]['receivename'],snapshot.data[index]['pgrpid'],snapshot.data[index]['prid'],snapshot.data[index]['message'],);
                          bool isgroup = true;
                          if (mychat.grpid == 0) {
                            isgroup = false;
                          }
                          return new ChatWidget(mychat: mychat,threaded: threaded, isgroup: isgroup);
                        },
                        itemCount: snapshot.data.length,
                      );
                    }
                }
              },
          ),
          onRefresh: _onRefresh
      ),
  )

This is built in the ChatWidget, you notice the _onTap:

new MyListTile(
              leading: new CircleAvatar(
                child: _chatAvatar(),
                //child: !isgroup ? _indMsg() : _grpMsg(), radius: 18.0,
              ),
              //subtitle: new Text(widget.mychat.oname),
              title: new Text(widget.mychat.referralname),
              trailing: new Text(widget.mychat.oname, textAlign: TextAlign.right,),
              //isThreeLine: true,
              //onTap: doTap(threaded),
              onTap: _onTap,
              onLongPress: _doArchive,
            ),
            new MyListTile(
              leading: new Text('        '),
              title: new Text(submymessage, textAlign: TextAlign.left,
                style: new TextStyle(fontSize: 15.0,
                    color: Colors.grey, fontStyle: FontStyle.italic),),
              trailing: _unreadBabdge(),
              onTap: _onTap,
              onLongPress: _doArchive,
            ),

That _onTap is below and has the code to handle the back button.

_onTap() async {
    ChatDB.instance.updateRead(widget.mychat.msgkey);
    if (threaded) {
      //TODO
    } else {
      Route route = new MaterialPageRoute(
        settings: new RouteSettings(name: "/ChatServerDivided"),
        builder: (BuildContext context) => new ChatServerDivided(mychat: widget.mychat, title: "Chat Messages",),
      );
      //Navigator.of(context).push(route);
      var nav = await Navigator.of(context).push(route);
      if(nav==true||nav==null){
        unread = ChatDB.instance.getUnread(widget.mychat.msgkey);
      }
    }


  }

So what I am trying to find is if this code can somehow commmunicate up to the originating widget so that I can run the original Future again. I hope this makes more sense and is easier to understand.

Robert
  • 5,347
  • 13
  • 40
  • 57
  • This is really confusing without an example ? – Shady Aziza Feb 06 '18 at 17:28
  • code added. This is the same page you helped me with before, but now I need to refresh data at the top on the same back and not sure how to call all the way back to the original Future. – Robert Feb 06 '18 at 18:06
  • I did not mean to post a full code, I am still confused about your question. Maybe just add a reduced case of what you are trying to achieve, a smaller experiment on dummy data so that anyone can follow easily. – Shady Aziza Feb 07 '18 at 07:17
  • If you look at this item you helped me with https://stackoverflow.com/questions/48582963/flutter-how-to-execute-when-clicking-back-button it works fine for the widget that has the route (ChatServerList in my code), however I need the top level to also refresh which in my code is the ChatServerPage widget. Not sure how to get the top level widget to refresh on the same back button click – Robert Feb 07 '18 at 12:57
  • Can you customize the example in the link to show what you mean? Just make it simpler for me because going through the whole code is going to be a hassle. Just create a dummy example to replicate your issue so I can follow. – Shady Aziza Feb 07 '18 at 13:16
  • made changes, hopefully it makes sense, too hard to try a simple example because of all the Futures, etc... – Robert Feb 07 '18 at 14:00
  • @aziza did you get a chance to look at my update explaining the code? Just wondering if you had any ideas. Thanks – Robert Feb 09 '18 at 15:13
  • I do not really understand :/ – Shady Aziza Feb 09 '18 at 19:07
  • So when the page runs initState runs, I use futurebuilder to uses a listview.builder, it calls a widget that creates the ListTile from another Future. I can refresh that data using the technique you showed me before, but what I need to do is go all the way to the top and run the same Future that is in my initState at the top, but can not figure out how to get all the way back there from the back button or other action like long press, etc... Does this help any? – Robert Feb 10 '18 at 12:53
  • Why are you using nested FutureBuilder ? and do you start your FutureBuilder in the initState ? – Shady Aziza Feb 10 '18 at 12:56
  • I nest the Future because there is 2 sets of data, I do call the first future in my initState _responseFuture = ChatDB.instance.getMessagesDates(widget.mychat.msgkey); and then there is another in the widget that is part of the ListView.builder. That is where I have the onTap with the function that runs on the back button and refreshes data in the ListTiles, but I need to be able to call all the way to the top and refresh the original data. – Robert Feb 11 '18 at 01:26
  • Are you sure about using nested FutureBuilder ? I still do not see why do you have to do it this way :/ – Shady Aziza Feb 11 '18 at 10:24
  • I am open to suggestions on how to get dynamic data based on the data returned from the first future. I need the ListView.builder and for each item there is also dynamic data based on a date in the first future. – Robert Feb 11 '18 at 12:11
  • How are you getting your data? http or database? why not use all relevant data in the same structure ? – Shady Aziza Feb 11 '18 at 13:30
  • I am getting data from local DB. I first get dates for messages and then for each date I then pull the messages for that particular date in order to build the tiles. No real way to get it all at once. It is 2 different datasets. – Robert Feb 11 '18 at 21:38
  • I am not sure about the value from separating the dates, you can have one big object and query on it based on the date to filter, I believe this is how databases should be structured in general. Regardless, does your database update regularly? if so, then you better of using StreamBuilder than FutureBuilder and it will save you the trouble of having to figure out how to update the view because using a SteamBuilder allows you to listen to data changes and auto-update accordingly. – Shady Aziza Feb 13 '18 at 06:44
  • Will give it a try – Robert Feb 13 '18 at 09:56
  • @aziza any idea how to convert a returned future to a stream? I am using sqflite plugin and it returns futures and not streams, trying to figure out how to return a stream so that I can try StreamBuilder. – Robert Feb 13 '18 at 15:26
  • I do not know this sounds convoluted. I think it is better if you restructure your data :/ – Shady Aziza Feb 13 '18 at 20:06

1 Answers1

4

Yes you can do that. Couldn't see exactly where to fit it into your code but I'll give you the way to handle this. The navigator calls are all Futures which means you can await them on the calling side. It seems like you're just missing passing a value to the .pop call. Below is an example.

Where you navigate you can await for your result

var navigationResult = await Navigator.push(
        context,
        new MaterialPageRoute(
            builder: (context) => Page2()));

Then you can check the navigationResult with a simple if.

if(navigationResult == 'rerun_future') {
    uploadFiles(); // Perform your custom functionality here.
 }

The way you pass that information back is that when you do a pop call (to navigate back) you'll pass the value 'rerun_future' in there.

Navigator.of(context).pop('rerun_future') 

Additionally if you also want to add this functionality to the back button you should surround your Scaffold with WillPopScope, return false to onWillPop and supply a leading item to the appBar where you perform your custom pop call. Example below from this post

@override
Widget build(BuildContext context) {
  return new WillPopScope(
    onWillPop: () async => false,
    child: new Scaffold(
      appBar: new AppBar(
        title: new Text("data"),
        leading: new IconButton(
          icon: new Icon(Icons.ac_unit),
          onPressed: () => Navigator.of(context).pop('rerun_future'), //<----- pass value here too
        ),
      ),
    ),
  );
}
Filled Stacks
  • 4,116
  • 1
  • 23
  • 36