Search code examples
flutterscoped-model

ScopedModel - how to pass more than one model


In sample we pass the single model like this

return ScopedModel<CounterModel>(
  model: CounterModel(), // only one model here
  child: MaterialApp(
    title: 'Scoped Model Demo',
    home: CounterHome('Scoped Model Demo'),
  ),
);

How to pass some models instead of single model? So that to use them later this way

Widget build(BuildContext context) {
    final username =
      ScopedModel.of<UserModel>(context, rebuildOnChange: true).username;
    final counter =
      ScopedModel.of<CounterModel>(context, rebuildOnChange: true).counter;

    return Text(...);
}

Solution

  • You can copy paste and run the full code below.
    You can reference this https://newcodingera.com/scoped-model-in-flutter/
    You can pass your three models and wrap them nested

    Code snippet

    void main() {
      runApp(MyApp(
        counterModel: CounterModel(),
        userModel: UserModel('Brian'),
        dataModel: DataModel('this is test'),
      ));
    }
    
    class MyApp extends StatelessWidget {
      final CounterModel counterModel;
      final UserModel userModel;
      final DataModel dataModel;
    
      const MyApp({
        Key key,
        @required this.counterModel,
        @required this.userModel,
        @required this.dataModel,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        // At the top level of our app, we'll, create a ScopedModel Widget. This
        // will provide the CounterModel to all children in the app that request it
        // using a ScopedModelDescendant.
        return ScopedModel<DataModel>(
          model: dataModel,
          child: ScopedModel<UserModel>(
            model: userModel,
            child: ScopedModel<CounterModel>(
              model: counterModel,
    

    Working demo

    enter image description here

    Full code

    import 'package:flutter/material.dart';
    import 'package:scoped_model/scoped_model.dart';
    
    void main() {
      runApp(MyApp(
        counterModel: CounterModel(),
        userModel: UserModel('Brian'),
        dataModel: DataModel('this is test'),
      ));
    }
    
    class MyApp extends StatelessWidget {
      final CounterModel counterModel;
      final UserModel userModel;
      final DataModel dataModel;
    
      const MyApp({
        Key key,
        @required this.counterModel,
        @required this.userModel,
        @required this.dataModel,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        // At the top level of our app, we'll, create a ScopedModel Widget. This
        // will provide the CounterModel to all children in the app that request it
        // using a ScopedModelDescendant.
        return ScopedModel<DataModel>(
          model: dataModel,
          child: ScopedModel<UserModel>(
            model: userModel,
            child: ScopedModel<CounterModel>(
              model: counterModel,
              child: MaterialApp(
                title: 'Scoped Model Demo',
                home: CounterHome('Scoped Model Demo'),
              ),
            ),
          ),
        );
      }
    }
    
    // Start by creating a class that has a counter and a method to increment it.
    //
    // Note: It must extend from Model.
    class CounterModel extends Model {
      int _counter = 0;
    
      int get counter => _counter;
    
      void increment() {
        // First, increment the counter
        _counter++;
    
        // Then notify all the listeners.
        notifyListeners();
      }
    }
    
    class UserModel extends Model {
      String _username;
    
      UserModel(String username) : _username = username;
    
      String get username => _username;
    
      set username(String newName) {
        _username = newName;
        notifyListeners();
      }
    }
    
    class DataModel extends Model {
      String _data;
    
      DataModel(String data) : _data = data;
    
      String get data => _data;
    
      set data(String newData) {
        _data = newData;
        notifyListeners();
      }
    }
    
    class CounterHome extends StatelessWidget {
      final String title;
    
      CounterHome(this.title);
    
      @override
      Widget build(BuildContext context) {
        final counter =
            ScopedModel.of<CounterModel>(context, rebuildOnChange: true).counter;
        final userModel = ScopedModel.of<UserModel>(context, rebuildOnChange: true);
        final dataModel = ScopedModel.of<DataModel>(context, rebuildOnChange: true);
    
        return Scaffold(
          appBar: AppBar(
            title: Text(title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('${userModel.username} pushed the button this many times:'),
                Text('${dataModel.data} From data model'),
                // Create a ScopedModelDescendant. This widget will get the
                // CounterModel from the nearest parent ScopedModel<CounterModel>.
                // It will hand that CounterModel to our builder method, and
                // rebuild any time the CounterModel changes (i.e. after we
                // `notifyListeners` in the Model).
                Text('$counter', style: Theme.of(context).textTheme.display1),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: RaisedButton(
                    child: Text('Change Username'),
                    onPressed: () {
                      userModel.username = 'Suzanne';
                    },
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: RaisedButton(
                    child: Text('Change Data'),
                    onPressed: () {
                      dataModel.data = 'data changed';
                    },
                  ),
                )
              ],
            ),
          ),
          // Use the ScopedModelDescendant again in order to use the increment
          // method from the CounterModel
          floatingActionButton: ScopedModelDescendant<CounterModel>(
            builder: (context, child, model) {
              return FloatingActionButton(
                onPressed: model.increment,
                tooltip: 'Increment',
                child: Icon(Icons.add),
              );
            },
          ),
        );
      }
    }