Giter VIP home page Giter VIP logo

scoped_model's People

Contributors

acrozes avatar apwilson avatar bcko avatar benwicks avatar brianegan avatar filiph avatar guidezpl avatar kevmoo avatar mono0926 avatar passsy avatar piinks avatar rspilker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

scoped_model's Issues

Get previous state, when state is updated

Hey :)

So is there a way to get the previous state, when an update arrives.
My use case is starting an animation, so i have for example a loading variable in my LoginModel, but i only want to trigger the animation when loading changed from false to true.
Is there a way to do this?

Best regards,
Mathew

Child models in a list listeners

Hello,

As far as i see, if chil List of some model is updated, parent does not notice that. To work around, i am calling notifyListeners of model from the widget. How bad is it and why?

Move to React Context naming

React just published the Context API with the same features as scoped_model. I was thinking about changing the names of scoped_model to conform the React names (Which are pretty good).

ScopedModel<AModel> -> ContextProvider<AModel>
ScopedModelDescendant<AModel> -> ContextConsumer<AModel>

//cc @apwilson

ScopedModelDescendant with Drawer and Navigator => model null

I have a super simple scenario where a ScopedModelDescendant's builder always has a null model.

Scenario is that I want to change app theme from a settings page, I navigate to the settings page via Navigator.of(ctx).push(SettingsPage).

The settings page has a ScopedModelDescendant to read/update current theme, but model is always null.

The ScopedModel is wrapping the main app.

Reproducer:
https://github.com/LarsKrogJensen/scoped_model

Broken link in README

I see that the original repo makes some changes so the link in the README is not pointing to where the code was extracted from anymore.

And I notice that the model has its own library now here: https://github.com/fuchsia-mirror/topaz/tree/master/public/lib/widgets/dart

And I was able to run the example in this repo with this fetching this dep:

dependencies:
  lib.widgets.dart:
    git:
      url: https://github.com/fuchsia-mirror/topaz.git
      path: public/lib/widgets/dart # for path from git: documentation is not merged yet: https://github.com/dart-lang/site-www/issues/314

as well as this import import 'package:lib.widgets.dart/model.dart';

Scoped model and pages splitted in different files

Hi, I have a problem with scoped model and multiple pages placed in different file. Let's say that I have a main.dart file with the HomePage and a second_page.dart file with SecondPage but I get the red screen error (Receiver:nulll - NoSuchMethodError: The getter 'foo' was called on null). If I take my SecondPage and I put it all in the main.dart, than all works. Is there a way to split pages in multiple file sharing the same model? Thanks

Create model that is not in main

I have an application which I don't want my model to be created in the beginning. I want to create my model etc when I am navigated to a logged in, state (Home.dart). Here I want to initialize the model, but when I try to find it with ScopedModelDescendant in a navigated class it returns null. How do I know if a widget is a child of a parent? And do I have to have the model at MaterialApp?

Connected to other model

Previously I was grateful for your hard work to develop this pattern.

I have a problem when I want to connect several models in a separate file. I previously worked with 'with' but an error appeared during the update.

But I found an answer for this:
#44 (using mixin and on)

in my case, the application works using this when the request is on the server, but dont understand why the error appears on the screen?

my code:
mixin ServiceModel on Model {}
mixin WishlistModel on ServiceModel{}
class MainModel extends Model with ServiceModel, WishlistModel {}

in main.dart:
final MainModel model = new MainModel();
return ScopedModel(
model: model,
...

Losing state on orientation change

I'm trying to use the scoped model for a subPage, but when the screen is recreated on an orientation change the state is lost.

I've put together a simple gist : here

If I move the scoped model above the material app then the data persists.
I'd wanted to have page scoped state and app scoped state, but when I've got data for a specific page I'm not sure how to get this working. It's most likely an issue in my code as I'm new to flutter, but I think an example like this would be handy for others too.

Difference between ScopedModel and InheritedModel?

Dear Brian, Could you please tell me what's the difference between the two? I want to build an app that has multiple (approx 8) models, and listen to specific model(s). I also wish to have some way to use imperative API, so that, for example, a button press could raise a notification or the like.

I will be really glad to know which of the two you think I should use.

Also: do ScopedModel and InheritedModel work well with built_value?

Login example

Hi, I am new to flutter. Do you have any login example which works together with the framework? Otherwise, could you please shed me some light how to do it or point me any reference for that?
Thanks in advance.

How to use load and persist json data in scoped model

I am trying to load json data using the scoped model like this:

import 'package:scoped_model/scoped_model.dart';
import 'package:flutter/services.dart' show rootBundle;

class MyModel extends Model {
  Map _jsonData;

  Future MyModel() async {
    // this won't work 
    String json =  await rootBundle.loadString('assets/words5.json');
     this._jsonData = json.decode(jsonString);
  }
  Map get jsonData => _jsonData;
}

After doing some research on stackoverflow, it was suggested I do something like this:

class MyModel extends Model {
  Map _jsonData;
  Future _doneFuture;

   MyModel()  {
      _doneFuture = _init();
   }

  Future _init() async {
    print('init');
    String jsonString = await _loadJsonFile();
    this._jsonData = json.decode(jsonString); 
  }

  Map get jsonData => _jsonData;
  Future get initializationDone => _doneFuture;

  Future<String> _loadJsonFile() async {
    return await rootBundle.loadString('assets/words.json');
  }

}

Future main() async {
 var c = new MyModel();
 await c.initializationDone;
 print('done');
  Widget app = new ScopedModel<CounterModel>(
 //.. 
)
}

Note that rootBundle returns a Future and that is, as far as I know, the only way to load files in Flutter.

I am running the newest Flutter and Dart 2 (Channel master, v0.3.1-pre.15, on Mac OS X 10.12.6 16G29, locale en-US) . Any idea how to load json data into my scoped model in Flutter?

Missing docs on best way to instantiate the ScopeModel widget when you have multiple models

The "Listening to multiple Models in a build function" doesn't cover how to instantiate the app for the first time, ie there's no multi-model equivalent of:

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

in the docs :-) Only solutions I found online boil down to creating a God object of all the model objects and then passing it to the main app widget in a ScopedModel<God> call (ie https://proandroiddev.com/you-might-not-need-redux-the-flutter-edition-9c11eba006d7, but also https://www.udemy.com/learn-flutter-dart-to-build-ios-android-apps/learn/v4/t/lecture/12309188?start=0 & others),

this is the only solution I found so far, I refuse to believe this is the truth (and it doesn't work with newer versions of Dart, you can't instantiate a mixin), so I'm hoping for some sage guidance from the Creators ^_^

Depending on context doesn't trigger rebuild/changes?

Using the second method ScopedModel.of. I'm able to change the state of the model but the changes do not update children accessing the model using context. It works if I use the scoped descendant widget. Is this the expected behavior.
I have a test for this,

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:scoped_model/scoped_model.dart';

void main() {
  testWidgets("model change should update children widgets depending on context", (WidgetTester tester) async {
    var testModel = new TestModel();

    var tree = new MaterialApp(
      home: new ScopedModel<TestModel>(
        model: testModel,
        child: new Container(
          child: TestWidget(),
        ),
      ),
    );

    // initial drawing shows the counter form the model
    await tester.pumpWidget(tree);
    expect(find.text('0'), findsOneWidget);
    // Increment the model, which should rebuild only the listening descendant subtree
    testModel.increment();
    await tester.pump();
    await tester.pump();

    // the text changes correctly
    expect(find.text("1"), findsOneWidget);
  });
}

class TestModel extends Model {
  int _counter;

  TestModel([int initialValue = 0]) {
    _counter = initialValue;
  }

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

  int get counter => _counter;

  void increment([int value]) {
    _counter++;
    notifyListeners();
  }
}

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var model = TestModel.of(context);
    return new Container(
      child: Text(model.counter.toString(), textDirection: TextDirection.ltr),
    );
  }
}

Fetch Json.

Hi, sorry, for not sharing code, i am used to use flutter_flux, wanted to give scoped model a shot , and see if it fits better, here is my use case scenario, a list view initial data fetched by json, each item on the list view might be updated on the fly, i mean i am using some sort of websockt with a like button on an item of the list, when data comes back holding the new value, i can notice some sort of glitch where the item would pop down and up really fast updating the value, #11 i have read here, and did sth similar with condition on db not empty. Secondly, am using some sort of waking up connectivity if an internet connection went down, doing that i can see a request sent requiring new like value and the new values are back on console too, but UI never updates, i did call notify on my model where it gets the new values and update db. well. if am doing it right, dose that mean scoped model is not suitable for my use case?

model.isLoading blocking transition

Hi - i have the below sample app using ScopedModel. I put an artificial delay of an async http call of 5 seconds, and i am noticing that after i call isLoading = true; notifyListeners(); , the transition "hangs". If i use a CircularProgressIndicator, it freezes until the future completes, if i use BottomNavigationBar, the "swipe in" completes half way, freezes, then finishes when future completes.

Is there a more idiomatic way to do this so that the page2 fully renders while the http future is running ?

//-----------------------
//main.dart
//-----------------------

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      routes: {
        '/' : (BuildContext context) => Page1(),
        '/page2' : (BuildContext context) => Page2()
      }
    );
  }
}

//-----------------------
//page1.dart
//-----------------------

class Page1 extends StatelessWidget {

  @override
    Widget build(BuildContext context) {
       return Scaffold(
         appBar: AppBar(title: Text('Page 1')),
         body: Container(
           child: Column(children: <Widget>[
             Text('Page 1 header'),
             RaisedButton(
               child: Text('Click me'),
               onPressed: ()  { 
                 Navigator.of(context).pushReplacementNamed('/page2');
                 })
           ],),)
         );
    }
}

//-----------------------
//page2.dart
//-----------------------

class Page2 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _Page2State();
  }
}

class _Page2State extends State<Page2> {
  MainModel model = MainModel();

  void initState() {
    model.fetchData();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('Page 2')),
        body: ScopedModel<MainModel>(
            model: model,
            child: ScopedModelDescendant(
                builder: (context, child, MainModel model) {
              if (model.isLoading) {
                return Center(child: CircularProgressIndicator());
              } else {
                return Container(
                    child: Column(
                  children: <Widget>[
                    Text('Page 2 body'),
                  ],
                ));
              }
            })));
  }
}


//-----------------------
//main_model.dart
//-----------------------
class MainModel extends Model {

    bool _isLoading = false;
    bool get isLoading => _isLoading;

  void fetchData() async {

      _isLoading = true;
      notifyListeners(); 

      final String url = 'https://jsonplaceholder.typicode.com/todos/1';

      await http.get(url)
          .then<Null>((http.Response response) {
            print('${DateTime.now()} In http response and about to sleep');
            sleep(const Duration(seconds:5));
            print('${DateTime.now()} done sleeping');
        
            _isLoading = false;
            notifyListeners();
            return;
          }
      ).catchError((error) {
        print('Error: $error');
        _isLoading = false;
        notifyListeners();
        return;
      });

  }
  
}

Docs missing lines

See the screenshot, it is missing lines in the docs.
However, I know rebuildOnChange tells you whether the ScopedModelDescendant's builder() method should get called when the model changes mentioned that we call notifyListeners() in the model.

image

Sending an action with notifyListeners()

Is there any reason the notifyListeners call cannot contain a parameter that listeners could use to determine what has been updated?

For example if I have two models that I am composing into a root or 'MainModel' via mixins it would be cool if I could have the MainModel listen for updates to the model and in turn persist the correct model data to disk as opposed to the entire model. For example:

class MainModel extends Model with UserModel, ProductsModel {
  Service service;

  MainModel(this.service) {
    addListener((String action) {
      if (action == 'USER_MODEL_UPDATED') {
        service.persistUserData(userData);
      } else if (action == 'PRODUCTS_MODEL_UPDATED') {
        service.persistProductData(productData);
      }
    });
  }
}

mixin UserModel on Model {
  userData;

  ...
}

mixin ProductsModel on Model {
  productsData;

  ...
}

Any thoughts on this?

Ability to connect multiple models in connector (ScopedModel)

I am a big fan of unstated which takes advantages of React's new Context API and shares many similarities to this library.

It would be nice if you could combine multiple models in the subscriber

new ScopedModel(
      model: [new BookModel(), new CounterModel()],
      child: new Column(children: [
        new ScopedModelDescendant(
                builder: (context, child, { bookModel, counterModel }) => new Text(
                    counterModel.counter.toString()),
              ),
        new Text("Another widget that doesn't depend on the CounterModel")
      ])

similar to how you can do it in unstated

<Subscribe to={[BookContainer, CounterContainer]}>
  {
    (bookStore, counterStore) => {
      // do stuff here
    }
  }
</Subscribe>

BuildContext InheritedWidget becomes null within a ScopedModel return object

Hello Brian,

I wanted to run this by you and see what you think.

I have an app where the MaterialApp which is wrapped by a ScopedModel and it's working perfectly 👍

I'm following this article to Create build environments in Flutter.

I've tested the code in a guinea pig flutter app and the code works fine. I'm running print statements of the inherited widget of AppConfig when initialized and the values are valid. But when the Material App is wrapped by a scoped model, the BuildContext objects within the scoped model have no idea of the Inherited Widget of AppConfig. The build contexts in the scoped model are completely different from the build contexts in the AppConfig Inherited Widget.

I'm not sure if this is a bug where ScopedModels aren't taking into account of the inherited widgets, or if there is some sort of call that has to be made in the ScopedModel files to abide by the inherited widget updating the application's BuildContext.

If you can shed any light on this, it'll be much appreciated. Thanks, Brian.

ScopedModel.of vs ScopedModelDescendant usage

I think the answers to these questions(mostly related to which widget rebuilds) would be a good extension to the documentation. I suggest we add some clarity with the usage including some advantages/disadvantages in our nice docs

I.

@override
Widget build(BuildContext context) {
  // ScopedModel.of<HomeModel>(context, rebuildOnChange: true); under the hood
  final model = HomeModel.of(context);
  return Scaffold(
    appBar: AppBar(
      title: Text(
        'A = model.countA}
      ),
    ),
  );
}

Question:
Will the whole Scaffold rebuild if model.countA's value changes? If not, which child widget will be rebuilt on value change?

II.

a.

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(
        'A = HomeModel.of(context).countA}
      ),
    ),
  );
}

b.

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: ScopedModelDescendant<HomeModel>(
        builder: (context, child, model) => Text(
          'A = ${model.countA}'
        ),
      ),
    ),
  );
}

Question:
Will a and b rebuild the same widget? Which is more performant?

Storing Translations inside Model

Is there anyway to store translations within the model itself, and have the strings refreshed when the locale changes?

List<String> activeFilters = [
      Translations.of(context).registrationState,
      Translations.of(context).contactInfo,
      Translations.of(context).customerStatus,
      Translations.of(context).effectiveYear,
      Translations.of(context).motor,
      Translations.of(context).property,
      Translations.of(context).travel,
      Translations.of(context).health
    ];

 Locale _appLocale = Locale('en');
 Locale get appLocale => _appLocale ?? Locale("en");

  void changeLocale(String langCode) {
    _appLocale = Locale(langCode);
    notifyListeners();
  }

Interact with model outside the widget.

I wanted to interact with the model when the animations are over , is there any way to have such interactions with scoped model

 var obj = new CounterModel();
  @override
  void initState() {
    super.initState();

    controller = new AnimationController(
        vsync: this, duration: new Duration(milliseconds: 3000));
    animation = new CurvedAnimation(parent: controller, curve: Curves.easeIn);
    animation.addListener(() {
      this.setState(() {


      });
    });
    animation.addStatusListener((AnimationStatus status) {
    if(status==AnimationStatus.completed){
     print("BELOW ISTHE CODE");
     model.increment(widget.widthRatio);

    }
    });
    controller.forward();

  }

Ask for clarification: ScopedModel Vs Model ?

I'm followinf a Udemy course using your package, but I thinks it's using a strange approach

Example: we have User model class

import 'package:meta/meta.dart';

class UserModel {
  final String id;
  final String email;
  final String password;

  UserModel({@required this.id, @required this.email, @required this.password});
}

Then we created a Scoped one

import 'package:scoped_model/scoped_model.dart';
import '../models/user_model.dart';

class ScopedUserModel extends Model {
  UserModel _authenticatedUsers;

  void login({String email, String password}) {
    _authenticatedUsers = UserModel(
        id: 'arararara', email: '[email protected]', password: 'ararara');
    notifyListeners();
  }
}

But we also have Product Model and Product Scoped Model.

Than I give it up, when I must use both of them

Why do we need a scoped class extending model and using our model class? To add listenable behaviour? This seems reasonable.

But what the right way to use both models without the chain of descendants? It's an hell.

Cource author is trying to use mixin, but Dart syntax for mixin already changed 3-4 times and now instructions are no more updated.

Asking for example in doc and a little more bit of theory

Cross-platform Support

Hey all,

One downside to scoped_model: It cannot be used for AngularDart / Dart Web apps because Model implements the Listenable interface from Flutter.

Proposal

Split scoped_model into 3 packages:

  1. scoped_model would contain only the Model class, which implements no interfaces.
  2. scoped_model_flutter would Import the Model class and use it for the ScopedModel / ScopedModelDescendant Widgets
  3. scoped_model_angular would provide a Pipe that can be used to listen for changes to a Model class, rebuilding the appropriate component on change. e.g. {{(myModel | listen).message}}

Pros

Makes the Model class Completely independent of Flutter, and can be re-used cross-platform.

Cons

  • Can't create a MyModel.of(BuildContext context) method directly on the Model if you want to use the library cross-platform. I don't know how common this is...
  • Not sure if folks are currently using scoped_model as a Listenable (such as with an AnimatedBuilder widget), or merging it with other Listenables via the Listenable.merge constructor.

Would love to hear your thoughts @passsy, @apwilson, @chimon2000 and others! Is anyone using the Model class as a Listenable?

Simple question about control widget values

I'm experimenting with the scoped_model system for designing an app, and I have a very simple question about how to initialize and change the value fields of widgets like DropDownButton and Switch.

I have a model structure that contains a list of options for the DropdownButton, I wrap the button in the ScopedModelDescendant so I can access the list within the model to create the DropdownMenuItem's necessary. However I need to give the DropdownButton an initial value that is mutable (so that selecting options updates the widget). I'm struggling to figure out where to store that variable and how to initialize it.

One option is to store in the local widget's state, but an initState() method does give me access to the existing list of categories in the model. If I put it in the build() method for the widget, it can access the model, but then I can't change it because the build() method will overwrite any changes made by the widget's setState(). I guess the third option would be to put a mutable variable in the model itself that reflects the state of the widget, but I'm not sure if that's following proper design principles.

I've created a small sample app below, and inserted my two questions with double stars (**)

import 'package:scoped_model/scoped_model.dart';

class MyAppModel extends Model {
  List<String> categories = ['A', 'B', 'C'];
}

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScopedModel<MyAppModel>(
        model: MyAppModel(),
        child: MaterialApp(
            home: Scaffold(
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('Dropdown button from model:'),
                MyAppDropdown(),
              ],
            ),
          ),
        )));
  }
}

class MyAppDropdown extends StatefulWidget {
  @override
  _MyAppDropdownState createState() => _MyAppDropdownState();
}

class _MyAppDropdownState extends State<MyAppDropdown> {
  @override
  Widget build(BuildContext context) {
    return ScopedModelDescendant<MyAppModel>(
      builder: (context, child, model) {
        return Container(
          child: DropdownButton(
            value: **"How do I insert a local mutable value from the model"**
            items: model.categories.map((String value) {
              return DropdownMenuItem<String>(value: value, child: Text(value));
            }).toList(),
            onChanged: **"How do I change that local mutable value"**,
          ),
        );
      },
    );
  }
}

Could not find the correct ScopedModel.

void main() {
  runApp(new MyApp());
}
class MyApp extends StatelessWidget {
 @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new HomePage(),
      onGenerateRoute: Routes.onGenerateRoute,
    );
  }
}
class HomePage extends StatelessWidget {
 @override
  Widget build(BuildContext context) {
    return ScopedModel<SampleScopedModel>(
      model: SampleScopedModel(),
      child: Scaffold(
        body: Container(),
        floatingActionButton: FloatingActionButton(onPressed: () {
          Navigator.pushNamed(context, "NextPage");
        }),
      ),
    );
  }
}
class NextPage extends StatelessWidget {
  @override
    Widget build(BuildContext context) {
      return ScopedModel<SampleScopedModel>(
        model: SampleScopedModel(),
        child: Scaffold(
          body: ScopedModelDescendant<SampleScopedModel>(
          builder: (context, child, model) {
            return Text(model.payload.toString());
          })
        ),
     );
    }
}
class SampleScopedModel extends Model {
  int _payload;

  int get payload => _payload;

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

  void setPayload(int payload) {
    this._payload = payload;
    notifyListeners();
  }
}

State with objects or lists

Hi,

I like the idea of scoped model but all the examples only use primitive states. How can I use a list of objects in the model and update a single property of a single element of that list?

class Dog {
  String name;
}

class MyModel extends Model {
  List<Dog> _dogs;

  List<Dog> get dogs => _dogs;

  //How can I change the name of a specific dog in the list?
}

I could add a changeName(index, newName) method but how can I do that if the objects are more complex and have 20+ properties? Do I have to create a changeProperty() method for every property?

Could not find the correct ScopedModel

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ScopedModel<AppModel>( model: new AppModel(), child: new MaterialApp( theme: ThemeData.light(), home: new DefaultTabController( length: 2, child: new Scaffold( appBar: new AppBar( title: new Text("title"), backgroundColor: Colors.pink, bottom: TabBar( tabs: <Widget>[ new Tab( text: "songs", icon: Icon(Icons.music_note), ), new Tab( text: "favorite", icon: Icon(Icons.favorite), ), ], ), ), drawer: new Drawer(), body: TabBarView( children: <Widget>[ new GridView.count( primary: false, crossAxisCount: 2, children: <Widget>[ new Carton(Assets.alqanas), new Carton(Assets.shoot), new Carton(Assets.alqanas), new Carton(Assets.shoot), new Carton(Assets.alqanas), new Carton(Assets.shoot), new Carton(Assets.alqanas), new Carton(Assets.shoot), ], ), new Center(child: new Text("favorite is here")), ], )), ), ), ); } }

class Carton extends StatelessWidget { final String imageUrl; Carton(this.imageUrl); @override Widget build(BuildContext context) { return new Column(children: [ ScopedModelDescendant<AppModel>( builder: (context, child, AppModel model) => new IconButton( icon: new Image.asset(imageUrl), iconSize: 10.0, onPressed: () { Future<void> bottomSheetAwaitClose = showModalBottomSheet<void>( context: context, builder: (BuildContext context) { return MusicR(); }, ); bottomSheetAwaitClose.then((void value) { model.playerStateOff(); }); }, ), ), SizedBox(height: 100.0), new Text("carton"), ]); } }

class AppModel extends Model { bool _playerState = false ; bool get getPlayerState => _playerState ; void playerStateOff (){ _playerState = false ; notifyListeners(); } void playerStateOn(){ _playerState = true ; notifyListeners() ; } }
I have imported all required packages but still getting this error : Could not find the correct ScopedModel

Idiomatic way to define a reactive function?

First off, thank you so much for creating this awesome package, it works very nicely! It fits the paradigm I'm used to with MobX and JavaScript. But one feature of MobX for which I couldn't find a counterpart is https://mobx.js.org/refguide/reaction.html and https://mobx.js.org/refguide/autorun.html, which allows you to define a function that is automatically run whenever a value changes.

In my case, I'd like to execute a Navigator.of(context).pushReplacementNamed('...') once the value of my model.isSignedIn boolean changes to true. In other words, once the user signs in, I'd like to redirect them to a members-only page.

I couldn't find a built-in way to do this in scoped_model, so I tried using a ValueNotifier but somehow I wasn't getting any notifications in my StatefulWidget. Another hacky way I was thinking of exploring was using a Timer to keep checking to see if model.isSignedIn changes, but is there a better way?

Thank you!

Is ScopedModelDescendant necessary?

When I use the second way to find model, page does not refresh.
code:

Widget build(BuildContext context) {
    final appModel = ScopedModel.of<AppModel>(context);

    return Scaffold(
      body: Row(
        children: <Widget>[
          Switch(
              value: appModel.isNight,
              onChanged: (bool value) {
                print('value:$value');
                appModel.changeTheme(value);
              }),
        ],
      ),
    );
  }

image

Switch has not changed,
but the first way is ok.
If you can, I would like to see a complete example of the second method. Thank you!

New Approach for using multiple model classes (former with)

Hi and Good Afternoon,
first thanks for your work. For me its the best balanced approach for handling state in flutter :)
This is actually not an issue of the lib but after updating Flutter, using 'with" to have separate model files is not supported anymore, what would be the best way - from the architects side (you)) to accomplish that.
In more complex apps having all logic in one file seems not appropriate and me personally dont like the Repository approach so much.
Any help appreciated.
Greets from Manila

model null

TLDR;
due to the wrong usage of imports, models can get "null"

i changed

import 'model.dart';

to

import 'package:scoped_model_test/model.dart';

and it works now.

Original Post:

i think its related to this issue but i can't really figure out how to do it anyway.

#10

The simple one file example works fine, but as soon as i start to refactor things out across multiple files things start to crash.

For simplicity i just took the initial example and split it to separate files

  • main.dart
  • MainSreen.dart
  • model.dart

all under the lib folder.

main.dart:

import 'model.dart';
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import 'package:scoped_model_test/MainScreen.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return new ScopedModel<CounterModel>(
      model: CounterModel(),
      child: new MaterialApp(
        home: MainScreen(),
      ),
    );
  }
}

MainScreen.dart

import 'model.dart';

import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';

class MainScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Material(
      child: new Padding(
        padding: const EdgeInsets.all(28.0),
        child: Column(
          children: <Widget>[
//            ScopedModelDescendant<CounterModel>(builder:(context, child, model) { return Text(model.counter.toString());}),
            ScopedModelDescendant<CounterModel>(
                builder:(BuildContext context, Widget child, CounterModel model) {
                  print("model: $model");
                  return MaterialButton(
                    child: Text("+"),
                    onPressed: () {print("click"); /*model.increment();*/},
                  );
                }
            )
          ],
        ),
      ),
    );
  }
}

model.dart

import 'package:scoped_model/scoped_model.dart';

class CounterModel extends Model {
  int _counter = 0;
  int get counter => _counter;
  void increment() {
    _counter++;
    notifyListeners();
  }
}

i expected to just missed an import due to the description in the other issue, but i don't think that's the case here, but i think it is somehow related.

EDIT:
The code above is coming from a reduced example i did for myself. If i 100% apply this to the original code from the example code https://github.com/brianegan/scoped_model/blob/master/example/lib/main.dart it works fine ... but i can't really spot the essential difference :/

working code

main.dart

import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import 'package:scoped_model_test/model.dart';
import 'package:scoped_model_test/CounterHome.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new ScopedModel<CounterModel>(
      model: new CounterModel(),
      child: new MaterialApp(
        title: 'Flutter Demo',
        theme: new ThemeData(
          primarySwatch: Colors.green,
        ),
        home: new CounterHome('Scoped Model Demo'),
      ),
    );
  }
}

model.dart

import 'package:scoped_model/scoped_model.dart';

class CounterModel extends Model {
  int _counter = 0;
  int get counter => _counter;
  void increment() {
    _counter++;
    notifyListeners();
  }
}

CounterHome.dart

import 'package:flutter/material.dart';
import 'package:scoped_model_test/model.dart';
import 'package:scoped_model/scoped_model.dart';

class CounterHome extends StatelessWidget {
  final String title;

  CounterHome(this.title);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(title),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              'You have pushed the button this many times:',
            ),
            new ScopedModelDescendant<CounterModel>(
              builder: (context, child, model) => new Text(
                  model.counter.toString(),
                  style: Theme.of(context).textTheme.display1),
            ),
          ],
        ),
      ),
      floatingActionButton: new ScopedModelDescendant<CounterModel>(
        builder: (context, child, model) => new FloatingActionButton(
          onPressed: model.increment,
          tooltip: 'Increment',
          child: new Icon(Icons.add),
        ),
      ),
    );
  }
}

EDIT2:

Ok i just figured out, that this had something to do with how the imports are made. I just followed the autocompletion in Android Studio and changed

import 'model.dart';

to

import 'package:scoped_model_test/model.dart';

i think i have to look up what this actually means in regards to dart (i am quite new to that language). I think i can close this for now and added a TLDR; on top.

I get an error when mixin 2 models to a main model

compiler message: lib/scoped-models/main.dart:6:17: Error: The type 'ProductsModel' can't be mixed in.

compiler message: class MainModel extends Model with UserModel, ProductsModel {}

compiler message: ^

compiler message: lib/scoped-models/main.dart:6:47: Error: Type 'ProductsModel' not found.

compiler message: class MainModel extends Model with UserModel, ProductsModel {}

compiler message: ^

compiler message: lib/scoped-models/main.dart:1: Error: The superclass, '_MainModel&Model&UserModel&ProductsModel', has no unnamed constructor that takes no arguments.


✓] Flutter (Channel beta, v0.8.2, on Mac OS X 10.13.6 17G2307, locale en-TH)
[✓] Android toolchain - develop for Android devices (Android SDK 28.0.1)
[✓] iOS toolchain - develop for iOS devices (Xcode 10.0)
[✓] Android Studio (version 3.1)
[✓] VS Code (version 1.27.2)
[✓] Connected devices (1 available)

How to test a widget that call an async method ?

When I test a ScopedModel widget that contains an async method ( model.update() ), there is an error:

A Timer is still pending even after the widget tree was disposed.
'package:flutter_test/src/binding.dart': Failed assertion: line 787 pos 7:
'_fakeAsync.nonPeriodicTimerCount == 0'

The widget I want to test:

class PostWidget extends StatelessWidget {
  const PostWidget();

  @override
  Widget build(BuildContext context) {
    return ScopedModel<PostModel>(
      model: PostModel(),
      child: Card(
        child: Container(
          child: ScopedModelDescendant<PostModel>(
              builder: (context, child, model) {
            if (model.api.isLoaded == true) {
              return const PostContentWidget();
            }
            if (model.api.isLoading == true) {
              return CircularProgressIndicatorCardWidget();
            }
            model.update();
            return Container();
          }),
        ),
      ),
    );
  }

The PostModel:

class PostModel extends Model {
  Post _post = new Post();
  Api _api = new Api();
  Post get post => _post;
  Api get api => _api;

  Future<void> update() async {
    if (_api.isLoading == true) return null;
    _api.isLoaded = false;
    _api.isLoading = true;
    notifyListeners();
    _post = await DI().rest.fetchPost();
    _api.isLoaded = true;
    _api.isLoading = false;
    notifyListeners();
  }
}

The test that fail:

void main() {
  testWidgets('PostWidget test', (WidgetTester tester) async {
    DI().configure(RestType.DUMMY);
    await tester.pumpWidget(new PostWidget());
    print('PostWidget test DONE');
  });
}

The error returned:


PostWidget test DONE
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following assertion was thrown running a test:
A Timer is still pending even after the widget tree was disposed.
'package:flutter_test/src/binding.dart': Failed assertion: line 787 pos 7:
'_fakeAsync.nonPeriodicTimerCount == 0'

Either the assertion indicates an error in the framework itself, or we should provide substantially
more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new

When the exception was thrown, this was the stack:
#2      AutomatedTestWidgetsFlutterBinding._verifyInvariants (package:flutter_test/src/binding.dart)
#3      TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:520:7)
<asynchronous suspension>
#6      TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:494:14)
#7      AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:751:24)
#13     AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:749:16)
#14     testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:62:24)
#15     Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test/src/backend/declarer.dart:161:27)
<asynchronous suspension>
#16     Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test/src/backend/invoker.dart:249:15)
<asynchronous suspension>
#20     Invoker.waitForOutstandingCallbacks (package:test/src/backend/invoker.dart:246:5)
#21     Declarer.test.<anonymous closure>.<anonymous closure> (package:test/src/backend/declarer.dart:159:33)
#25     Declarer.test.<anonymous closure> (package:test/src/backend/declarer.dart:158:13)
<asynchronous suspension>
#26     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test/src/backend/invoker.dart:403:25)
<asynchronous suspension>
#40     _Timer._runTimers (dart:isolate/runtime/libtimer_impl.dart:382:19)
#41     _Timer._handleMessage (dart:isolate/runtime/libtimer_impl.dart:416:5)
#42     _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:165:12)
(elided 28 frames from class _AssertionError, class _FakeAsync, package dart:async, and package
stack_trace)

The test description was:
PostWidget test
════════════════════════════════════════════════════════════════════════════════════════════════════

Test failed. See exception logs above.
The test description was: PostWidget test

How can I fix that error ?
Thank you.

State is not preserved after Hot Reload

Seems like the model is recreated when Hot Reload occurs which is quite detrimental when your doing quick changes and cannot see them getting applied correctly, ex: User login information gets lost thus you cannot visualize how the user profile would look when the missing information is present.

Is this by design or an issue?

Dart 2 Support

It would seem scoped_model targets Dart SDK < 2.0.0, which means it will begin to cause compilation issues for people as they upgrade their projects to dart 2

TextFormField resets model

If you use a combination of TextFormFields and Int counters when the text field gets focused the model gets reset.

Model:

import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';

import '../../util/format_money.dart';

class TipCalcModel extends Model {
  int _tip = 18;
  int _people = 1;
  double _bill = 0.0;

  int get tip => _tip;
  int get people => _people;
  double get bill => _bill;

  set tip(int value) {
    _tip = value;
    notifyListeners();
  }

  set people(int value) {
    _people = value;
    notifyListeners();
  }

  set bill(double value) {
    _bill = value;
    notifyListeners();
  }

  double _calcTip() {
    return (((tip ?? 18.0) / 100) * _bill) / _people;
  }

  String calcTipTotal() {
    return formatMoney(_calcTip());
  }

  String calcBillTotal() {
    double _amountTotal = (_calcTip() + _bill) / _people;
    return formatMoney(_amountTotal);
  }
}

Screen:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:native_widgets/native_widgets.dart';
import 'package:scoped_model/scoped_model.dart';

import '../../models/calcs/tip.dart';
import '../../util/dismiss_keyboard.dart';
import '../../util/new_line.dart';
import '../../util/popUp.dart';
import '../../widgets/circle_icon.dart';
import '../../widgets/spacer.dart';

class TipCalculator extends StatelessWidget {
  static String routeName = "/tip_calc";

  static final GlobalKey<FormState> formKey = GlobalKey<FormState>();
  static final GlobalKey<FormFieldState<String>> billKey =
      GlobalKey<FormFieldState<String>>();

  @override
  Widget build(BuildContext context) {
    return new ScopedModel<TipCalcModel>(
      model: TipCalcModel(),
      child: Scaffold(
        appBar: AppBar(
          title: Text(
            'Tip Calculator',
            style: Theme.of(context)
                .textTheme
                .headline
                .copyWith(color: Colors.white),
          ),
          elevation: 0.0,
        ),
        body: ScopedModelDescendant<TipCalcModel>(
          builder: (context, child, model) => SafeArea(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: ListView(children: <Widget>[
                    Form(
                      key: formKey,
                      autovalidate: false,
                      onWillPop: () {
                        return Future(() => true);
                      },
                      child: ListTile(
                        leading: Icon(FontAwesomeIcons.moneyBill),
                        title: TextFormField(
                          key: billKey,
                          autofocus: true,
                          style: Theme.of(context).textTheme.headline,
                          keyboardType: TextInputType.numberWithOptions(),
                          decoration: InputDecoration(labelText: 'Bill Total'),
                          validator: (val) => val.trim().isEmpty
                              ? 'Total of the Bill Required'
                              : null,
                        ),
                      ),
                    ),
                    spacer,
                    ListTile(
                      leading: Icon(FontAwesomeIcons.percentage),
                      title: Text(
                        model.tip.toString() + "%",
                        maxLines: 1,
                        style: Theme.of(context)
                            .textTheme
                            .display1
                            .copyWith(fontSize: 27.0),
                      ),
                      onTap: () {
                        showAlertPopup(context, "Info",
                            "Tip Amount. $newLine\Averages 18-20 %");
                      },
                      trailing: ButtonBar(
                        mainAxisSize: MainAxisSize.min,
                        children: <Widget>[
                          circleIconButton(
                              icon: FontAwesomeIcons.minus,
                              onPressed:
                                  model.tip == 0 ? null : () => model.tip--),
                          circleIconButton(
                              icon: FontAwesomeIcons.plus,
                              onPressed:
                                  model.tip == 100 ? null : () => model.tip++),
                        ],
                      ),
                    ),
                    spacer,
                    ListTile(
                      leading:
                          Icon(model.people == 1 ? Icons.person : Icons.people),
                      title: Text(
                        model.people.toString(),
                        style: Theme.of(context)
                            .textTheme
                            .display1
                            .copyWith(fontSize: 27.0),
                      ),
                      onTap: () {
                        var _message =
                            "Number of People to Split the Check With.$newLine";
                        if (model.people == 1) {
                          _message += " Currently just you.";
                        } else if (model.people == 2) {
                          _message +=
                              " Currently you plus ${model.people - 1} other person.";
                        } else {
                          _message +=
                              " Currently you plus ${model.people - 1} people.";
                        }
                        showAlertPopup(context, "Info", _message);
                      },
                      trailing: ButtonBar(
                          mainAxisSize: MainAxisSize.min,
                          children: <Widget>[
                            circleIconButton(
                                icon: FontAwesomeIcons.minus,
                                onPressed: model.people == 1
                                    ? null
                                    : () => model.people--),
                            circleIconButton(
                                icon: FontAwesomeIcons.plus,
                                onPressed: () => model.people++),
                          ]),
                    ),
                    spacer,
                    NativeButton(
                      onPressed: () {
                        final _bill = billKey.currentState.value;
                        model.bill = double.tryParse(_bill);
                        final form = formKey.currentState;
                        if (form.validate()) {
                          dismissKeyboard(context);
                          showModalBottomSheet<void>(
                              context: context,
                              builder: (BuildContext context) {
                                return SafeArea(
                                    child: Column(
                                  mainAxisSize: MainAxisSize.min,
                                  children: <Widget>[
                                    ListTile(
                                      title: Text(
                                        model.people == 1
                                            ? "Amount Due"
                                            : "Per Person",
                                        style: Theme.of(context)
                                            .textTheme
                                            .headline,
                                      ),
                                    ),
                                    ListTile(
                                      leading:
                                          Icon(FontAwesomeIcons.percentage),
                                      title: Text(
                                        "Tip: " + model.calcTipTotal(),
                                        style: Theme.of(context)
                                            .textTheme
                                            .headline,
                                      ),
                                    ),
                                    ListTile(
                                      leading: Icon(FontAwesomeIcons.moneyBill),
                                      title: Text(
                                        "Total: " + model.calcBillTotal(),
                                        style: Theme.of(context)
                                            .textTheme
                                            .headline,
                                      ),
                                    ),
                                    ListTile(
                                      leading: Icon(Icons.info),
                                      title: Text(
                                        "Increase the Tip Percentage for Good Service",
                                        style:
                                            Theme.of(context).textTheme.body1,
                                      ),
                                      subtitle: Text(
                                        'Poor: 16%, Good: 18%, Great: 20%',
                                      ),
                                    ),
                                  ],
                                ));
                              });
                        }
                      },
                      buttonColor: Colors.blue,
                      child: Text('Calculate'),
                    ),
                  ]),
                ),
              ),
        ),
      ),
    );
  }
}

Merge "provider" and "scoped_model"

provider is an alternative to inherited widgets management.

Both provider and scoped_model aims at doing the same thing, which provider having a slightly larger vision:

provider is not limited to exposing a Model and works with potentially anything, including BLoC, streams, and others.

On the other hand, scoped_model is a lot more popular than provider.


The state of things is pretty confusing for the community.

scoped_model is not enough for advanced inherited widgets, but provider has a too small reach for peoples to find the package.

Would this make sense to merge both packages?

provider already implements the same features as scoped_model but with different names.
provider could expose aliases of its implementations to match scoped_model names to make the merging non-breaking.

navigate to new route from model

Is there a way to navigate to a new route from the model (not from the page widget)?

I need to navigate out of the screen on some logical condition (as oppose to user action)
Is there a way to do it directly from the model logic?

Currently I setup a flag in the model and use it to show a "finish" button to the user where the navigation happens (onPressed), but I would like to navigate without the user's interaction.

Thank you

Todo Example, update a single todo will make the whole todo list re-render.

I am a newbie to flutter.

I found the TodosModel is a big model include all todos in the list, so there is no todoUpdated or todoListUpdated.

is that possible I can distinguish this 2 updates? so I could just re-build the updated todo item, not the all todo list? It should make the performance better.

Could you share us an example for that?

Error: Could not find the correct ScopedModel.

// this is my SignUp.dart file

import 'package:flutter/material.dart';
import 'dart:async';
import '../model/SignedUpList.dart';
import '../scoped_model/signupmodel.dart';
import 'package:scoped_model/scoped_model.dart';

class SignUp extends StatefulWidget {
@OverRide
State createState() {
// TODO: implement createState
return SignUpPage();
}
}

class SignUpPage extends State {

final myController = TextEditingController();

FocusNode EmailFocusNode = new FocusNode();
FocusNode PasswordFocusNode = new FocusNode();
FocusNode ConfirmFocusNode = new FocusNode();

List list=[];

@OverRide
void dispose() {
// Clean up the controller when the Widget is disposed
myController.dispose();
super.dispose();
}

final GlobalKey _formKey = GlobalKey();

final Map<String, dynamic> _formData = {
'username': null,
'email': null,
'password': null,
};

Widget _buildusername() {
return TextFormField(
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0.0)),
borderSide: BorderSide(color: Colors.orange)),
hintText: 'Username',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0.0)),
)),
keyboardType: TextInputType.text,
onEditingComplete: () {
FocusScope.of(context).requestFocus(EmailFocusNode);
},
validator: (String value) {
if (value.trim().length <= 0) {
return 'Please enter a Username';
}
},
onSaved: (String value) {
_formData['username'] = value;
},
);
}

Widget _buildgradientbutton(double targetWidth) {
return ScopedModelDescendant(
builder: (BuildContext context,Widget child,signupmodel model){
return
/model.isLoading?
Center(child: CircularProgressIndicator()):
Container(
width: targetWidth,
height: 50.0,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.red, Colors.orange],
),
boxShadow: [
BoxShadow(
color: Colors.grey[500],
offset: Offset(0.0, 1.5),
blurRadius: 1.5,
),
]),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: _submitForm(model.save_signup_form),
//onTap: this.onPressed,
child: Center(
child: Text(
'Sign Up',
style: TextStyle(color: Colors.white),
),
)),
),
)
/;
}

);

}

Widget buildemail() {
return TextFormField(
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0.0)),
borderSide: BorderSide(color: Colors.orange)),
hintText: 'E-Mail',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0.0)),
),
filled: true,
fillColor: Colors.white),
keyboardType: TextInputType.emailAddress,
focusNode: EmailFocusNode,
onEditingComplete: () {
FocusScope.of(context).requestFocus(PasswordFocusNode);
},
validator: (String value) {
if (value.isEmpty ||
!RegExp(r"[a-z0-9!#$%&'*+/=?^
{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_{|}~-]+)*@(?:a-z0-9?.)+a-z0-9?")
.hasMatch(value)) {
return 'Please enter a valid email';
}
},
onSaved: (String value) {
_formData['email'] = value;
},
);
}

Widget _buildpassword() {
return TextFormField(
controller: myController,
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0.0)),
borderSide: BorderSide(color: Colors.orange)),
hintText: 'Password',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0.0)),
),
),
obscureText: true,
focusNode: PasswordFocusNode,
onEditingComplete: (){
FocusScope.of(context).requestFocus(ConfirmFocusNode);
},
validator: (String value) {
if (value.isEmpty || value.length < 6) {
return 'Password invalid';
}
},
onSaved: (String value) {
_formData['password'] = value;
},
);
}

Widget _buildconfirmpassword() {
return TextFormField(
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0.0)),
borderSide: BorderSide(color: Colors.orange)),
hintText: 'Confirm Password',
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0.0)),
),
),
obscureText: true,
focusNode: ConfirmFocusNode,
onEditingComplete: (){

    _submitForm(signupmodel().save_signup_form);

    /* setState(() {
      _submitForm(signupmodel().save_signup_form);
      signupmodel().isLoading=true;
    });*/

    },
  validator: (String value) {
    if (value != myController.text) {
      print(value);
      return 'Passwords not matching';
    }
    //dispose();
  },
);

}

_submitForm(Function save_signup_form) {

if (!_formKey.currentState.validate()) {
  return;
}
_formKey.currentState.save();
print(_formData);
save_signup_form(_formData['username'],_formData['email'],_formData['password']).then((bool success) {
  if (success) {
    Navigator.pushReplacementNamed(context, '/');
  } else {
    showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text('Something went wrong'),
            content: Text('Please try again!'),
            actions: <Widget>[
              FlatButton(
                onPressed: () => Navigator.of(context).pop(),
                child: Text('Okay'),
              )
            ],
          );
        });
  }
});
//Navigator.pushReplacementNamed(context, '/Log_In');

}

void _loginpage() {
Navigator.pushReplacementNamed(context, '/');
}

Future _backButtonpressed() async{

Navigator.of(context).pop();

}
@OverRide
Widget build(BuildContext context) {
// TODO: implement build

final double deviceWidth = MediaQuery.of(context).size.width;
final double targetWidth = deviceWidth > 550.0 ? 500.0 : deviceWidth * 0.95;
return WillPopScope(
    onWillPop: _backButtonpressed,
    child:Scaffold(
  appBar: AppBar(
      backgroundColor: Colors.white,
      elevation: 0.0,
      title: Center(
        child: Text('Sign Up'),
      )),
  body: Container(
    decoration: BoxDecoration(color: Colors.white),
    padding: EdgeInsets.all(10.0),
    child: Center(
      child: SingleChildScrollView(
        child: Container(
          width: targetWidth,
          child: Form(
            key: _formKey,
            child: Column(
              children: <Widget>[
                _buildusername(),
                _buildemail(),
                _buildpassword(),
                _buildconfirmpassword(),
                SizedBox(
                  height: 10.0,
                ),
                _buildgradientbutton(targetWidth),
              ],
            ),
          ),
        ),
      ),
    ),
  ),
  bottomNavigationBar: FlatButton(
      child: Text('Sign In'), onPressed: _loginpage),
)
);

}
}

//this is myscopedmodel signupmodel

import 'package:scoped_model/scoped_model.dart';
import '../model/SignedUpList.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';

class signupmodel extends Model{

bool isLoading;
List list=[];

Future save_signup_form(String _username,String _email,String _password,) async{

isLoading=true;
notifyListeners();
final Map<String, dynamic> _signupData = {
  'username': _username,
  'email': _email,
  'password':_password,
};
try {
  final http.Response response = await http.post(
      'https://sample-f765a.firebaseio.com/signuplist.json',
      body: json.encode(_signupData));

  if (response.statusCode != 200 && response.statusCode != 201) {
    isLoading = false;
    notifyListeners();
    return false;
  }
  final Map<String, dynamic> responseData = json.decode(response.body);
  print(responseData);
  isLoading = false;
  notifyListeners();
  return true;
  
} catch (error) {
  isLoading = false;
  notifyListeners();
  return false;
}

}
}

function consecutive running in Scoped Model

Hi
i have problem , when call a Future function from outside of Scoped Model ,that is run and run ...
how can i call that just for run once ?

//// function in Scoped model /////

Future fetchSelectedProducts(String categoryid) async {
  print("Run Fetch for $categoryid");
  selectedProductData.clear();
  isLoading = true;
  notifyListeners();
  final response =
      await http.get('https://....');
  List<dynamic> data = json.decode(response.body);
  ProductModel products = ProductModel();
  data.forEach((dynamic protdata) {
    products = ProductModel(
        product_id: protdata['product_id'],
        product_name: protdata['product_name'],
        product_category: protdata['product_category'],
        product_des: protdata['product_des'],
        product_color: protdata['product_color'],
        product_size: protdata['product_size'],
        product_barcode: protdata['product_barcode'],
        product_image: protdata['product_image'],
        product_count: protdata['product_count'],
        product_price_buy: protdata['product_price_buy'],
        product_price_sell: protdata['product_price_sell']);

    if (products.product_category == categoryid) {
      selectedProductData.add(products);
      print("Found:${products.product_category}");
    } else
      print("NotFound");

    notifyListeners();
  });

  isLoading = false;
  notifyListeners();
  return productData;
}

//// call fetchSelectedProducts function in outside widget ////

 @override
  Widget build(BuildContext context) {
    if (widget.currentcategoryID == "0") {
      return Container(
        child: Text("Show All Products"),
      );
    } else {
      runFetchSelectetProduct(widget.currentcategoryID);
      print(
          "Run GridView Product lentgh : ${widget.model.selectedProductData.length} ");
      return Container(
        child: Text("Show ${widget.currentcategoryID} Product"),
      );
       }
  }
}

runFetchSelectetProduct(categoryid) {
    widget.model.fetchSelectedProducts(categoryid);
 
    print("Run Fetch Selected Product Id:$categoryid");
  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.