scoped_model 1.0.1

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 100

scoped_model

Build Status codecov

A set of utilities that allow you to easily pass a data Model from a parent Widget down to it's descendants. In addition, it also rebuilds all of the children that use the model when the model is updated. This library was originally extracted from the Fuchsia codebase.

This Library provides three main classes:

  • The Model class. You will extend this class to create your own Models, such as SearchModel or UserModel. You can listen to Models for changes!
  • The ScopedModel Widget. If you need to pass a Model deep down your Widget hierarchy, you can wrap your Model in a ScopedModel Widget. This will make the Model available to all descendant Widgets.
  • The ScopedModelDescendant Widget. Use this Widget to find the appropriate ScopedModel in the Widget tree. It will automatically rebuild whenever the Model notifies that change has taken place.

This library is built upon several features of Flutter:

  • The Model class implements the Listenable interface
    • AnimationController and TextEditingController are also Listenables
  • The Model is passed down the Widget tree using an InheritedWidget. When an InheritedWidget is rebuilt, it will surgically rebuild all of the Widgets that depend on it's data. No need to manage subscriptions!
  • It uses the AnimatedBuilder Widget under the hood to listen to the Model and rebuild the InheritedWidget when the model changes.

Examples

  • Counter App - Introduction to the tools provided by Scoped Model.
  • Todo App - Shows how to write a Todo app with persistence and tests.

Usage

Let's demo the basic usage with the all-time favorite: A counter example!

// Start by creating a class that holds some view the app's state. In
// our example, we'll have a simple counter that starts at 0 can be 
// incremented.
//
// 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();
  }
}

// Create our App, which will provide the `CounterModel` to 
// all children that require it! 
class CounterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // First, create a `ScopedModel` widget. This will provide 
    // the `model` to the children that request it. 
    return new ScopedModel<CounterModel>(
      model: new CounterModel(),
      child: new Column(children: [
        // Create a ScopedModelDescendant. This widget will get the
        // CounterModel from the nearest ScopedModel<CounterModel>. 
        // It will hand that model to our builder method, and rebuild 
        // any time the CounterModel changes (i.e. after we 
        // `notifyListeners` in the Model). 
        new ScopedModelDescendant<CounterModel>(
          builder: (context, child, model) => new Text('${model.counter}'),
        ),
        new Text("Another widget that doesn't depend on the CounterModel")
      ])
    );
  }
}

Finding the Model

There are two ways to find the Model provided by the ScopedModel Widget.

  1. Use the ScopedModelDescendant Widget. It will find the Model and run the builder function whenever the Model notifies the listeners.
  2. Use the ScopedModel.of static method directly. To make this method more readable for frequent access, you can consider adding your own of method to your own Model classes like so:
class CounterModel extends Model {
  // ...
 
  /// Wraps [ScopedModel.of] for this [Model].
  static CounterModel of(BuildContext context) =>
      ScopedModel.of<CounterModel>(context);
}

Listening to multiple Models in a build function

In many cases, it makes sense to split your Models apart into logical components by functionality. For example, rather than having an AppModel that contains all of your application logic, it can often make more sense to split models apart into a UserModel, a SearchModel and a ProductModel, for example.

However, if you need to display information from two of these models in a single Widget, you might be wondering how to achieve that! To do so, you have two options:

  1. Use multiple ScopedModelDescendant Widgets
  2. Use multiple ScopedModel.of calls. No need to manage subscriptions, Flutter takes care of all of that through the magic of InheritedWidgets.
class CombinedWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final username =
      ScopedModel.of<UserModel>(context, rebuildOnChange: true).username;
    final counter =
      ScopedModel.of<CounterModel>(context, rebuildOnChange: true).counter;

    return Text('$username tapped the button $counter times');
  }
}

Contributors

Changelog

1.0.1

  • Fix changelog

1.0.0

  • Deprecated the ModelBuilder class. Use AnimatedBuilder instead, which works with any listenable.
  • Ship 1.0, since core functionality has been stable for quite some time.

0.3.0

  • Add constraint for Dart SDK (>=2.0.0-dev-28.0 <3.0.0)
  • Update / add lots of docs
  • Expose the ModelLister publicly, renamed to ModelBuilder
  • Add helpful error message if model could not be found

0.2.0

  • Thanks to @passsy for the contributions!
  • Model cannot be null
  • Model now implements Listenable
  • Improve Docs
  • Improve tests

0.1.1

  • Move to github

0.1.0

  • Initial version

example/README.md

example

A new Flutter project.

Getting Started

For help getting started with Flutter, view our online documentation.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  scoped_model: ^1.0.1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter packages get

Alternatively, your editor might support flutter packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:scoped_model/scoped_model.dart';
  
Version Uploaded Documentation Archive
1.0.1 Nov 29, 2018 Go to the documentation of scoped_model 1.0.1 Download scoped_model 1.0.1 archive
1.0.0 Nov 29, 2018 Go to the documentation of scoped_model 1.0.0 Download scoped_model 1.0.0 archive
0.3.0 Aug 17, 2018 Go to the documentation of scoped_model 0.3.0 Download scoped_model 0.3.0 archive
0.2.0 Jan 4, 2018 Go to the documentation of scoped_model 0.2.0 Download scoped_model 0.2.0 archive
0.1.1 Nov 25, 2017 Go to the documentation of scoped_model 0.1.1 Download scoped_model 0.1.1 archive
0.1.0 Aug 17, 2017 Go to the documentation of scoped_model 0.1.0 Download scoped_model 0.1.0 archive
Popularity:
Describes how popular the package is relative to other packages. [more]
99
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
100
Learn more about scoring.

We analyzed this package on Dec 5, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.1.0
  • pana: 0.12.7
  • Flutter: 1.0.0

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.28.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11
meta 1.1.6
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test