oliverbytes
oliverbytes

Reputation: 644

How to call a function of the 1st Page from the 3rd Page in Flutter?

I basically need to call a function from another page. This is my navigation structure: 1st Screen > 2nd Screen > 3rd Screen.

I have read many topics about my problem already but I can't get the perfect answer yet. I have tried using ScopedModel and InheritedWidgets but it requires a Widget on the tree just to pass data.

I am using the Navigator's named routes with pushNamed() function to push these pages.

Let's say my 1st screen has a listview and a function to refresh it: void refresh(). How can I call the refresh() function directly from the 3rd Screen?

Upvotes: 0

Views: 2342

Answers (2)

oliverbytes
oliverbytes

Reputation: 644

I have found the perfect solution already. I have to use the scoped_model package, create a model to be used as the data source for my ListView and it should be automatically updated anywhere in my app if I try to change the values of my model. And a static way of doing it without using a ScopedModelDescendant Widget is by calling this ScopedModel.of<MyModel>(context, rebuildOnChange: true).refresh();

model.dart file

class DataModel extends Model {
  bool _loading = false;

  String _data = "";

  bool get loading => _loading;
  String get data => _data;

  void refresh() {
    this._loading = true;
    print("loading...");
    notifyListeners();

    String url = "https://reqres.in/api/users/2?delay=1";
    http.get(url).then((response) {
      _loading = false;
      print("refreshed data: ${response.body}");
      this._data = response.body;
      notifyListeners();
    });
  }

  static DataModel of(BuildContext context) =>
      ScopedModel.of<DataModel>(context);
}

main.dart file

void main() => runApp(MyApp(model: DataModel()));

class MyApp extends StatelessWidget {
  final DataModel model;
  const MyApp({Key key, @required this.model}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ScopedModel<DataModel>(
      model: model,
      child: MaterialApp(
        title: 'ScopedModel Demo',
        routes: {
          '/': (_) => MyHomePage(title: 'Home Page'),
          '/settings': (_) => SettingsPage(),
        },
      ),
    );
  }
}

home.dart file

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
    void initState() {
      // I can fetch new data here statically without the use of the ScopedModelDescendant in the widget tree.
      DataModel.of(context).refresh();
      super.initState();
    }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ScopedModelDescendant<DataModel>(
        builder: (context, child, model) {
          return Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(model.loading ? "LOADING..." : ""),
                Text("data: ${model.data}"),
                // Statically reading the value from the model
                RaisedButton(child: Text("Read value statically"), onPressed: () {
                  String value = DataModel.of(context).data;
                  print("$value");
                },),
                RaisedButton(child: Text("Settings"), onPressed: () {
                  Navigator.pushNamed(context, "/settings");
                },)
              ],
            ),
          );
        },
      ),
      floatingActionButton: ScopedModelDescendant<DataModel>(
        builder: (context, child, model) {
          return FloatingActionButton(
            child: Icon(Icons.refresh),
            onPressed: () {
              // here is the ScopedModelDescendant version of refreshing data
              model.refresh();
            },
          );
        },
      ),
    );
  }
}

Upvotes: 0

Epizon
Epizon

Reputation: 189

You can do this multiple ways Some of the common ways are

  1. Pass the function down through constructors and call it
  2. Use rxDart
  3. Use scoped_model or any state management library

Upvotes: 1

Related Questions