Comments (3)
Hey, happy to help. Do you happen to have any code you could share?
One common mistake I've seen with ScopedModel / InheritedWidget usage is that you might be accidentally referencing the context which is a parent to the ScopedModel, rather than a context that includes the ScopedModel.
For example, trying to show a Snackbar in this way won't quite work because of the same problem:
class MyHomePage extends StatelessWidget {
final String title;
const MyHomePage({Key key, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Broken Button'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// This will fail, because we're referencing a context that doesn't include the Scaffold
Scaffold.of(context).showSnackBar(SnackBar(content: Text('Hi')));
},
child: Icon(Icons.add),
),
);
}
}
The fix? Wrap the FloatingActionButton in a new Widget, which will create a new context
that includes the Scaffold!
class MyHomePage extends StatelessWidget {
final String title;
const MyHomePage({Key key, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Broken Button'),
),
floatingActionButton: new MyButton(),
);
}
}
class MyButton extends StatelessWidget {
const MyButton({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return FloatingActionButton(
onPressed: () {
Scaffold.of(context).showSnackBar(SnackBar(content: Text('Hi')));
},
child: Icon(Icons.add),
);
}
}
Not sure if this was your problem, just one I commonly see! If you've got another issue going on, please let me know and it'd be great to have some code so I could take a look :)
I'm definitely open to the possibility there's a bug somewhere!
from scoped_model.
Hey there -- sorry about such a long delay :/ Was super busy in July then dropped the ball on this one.
Hrm, I'm not 100% sure what could be going wrong. As a test, I made the following example and it seems to work fine.
One other common problem: You need to ensure you're importing all files with their full package path, otherwise Dart can resolve the class incorrectly.
For example, in main.dart
, rather than doing an import 'app_config.dart';
use import 'package:my_app/app_config.dart';
. You can see other's who've run into this bug here: #15 and the Issue for the Dart team here: dart-lang/sdk#33076
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
class AppConfig extends InheritedWidget {
final String apiURL;
AppConfig({
@required this.apiURL,
@required Widget child,
}) : super(child: child);
static AppConfig of(BuildContext context) {
return context.inheritFromWidgetOfExactType(AppConfig);
}
@override
bool updateShouldNotify(InheritedWidget oldWidget) => false;
}
void main() {
runApp(AppConfig(
apiURL: 'hello',
child: MyApp(
model: CounterModel(),
),
));
}
class MyApp extends StatelessWidget {
final CounterModel model;
const MyApp({Key key, @required this.model}) : 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<CounterModel>(
model: model,
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 CounterHome extends StatelessWidget {
final String title;
CounterHome(this.title);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
// 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).
ScopedModelDescendant<CounterModel>(
builder: (context, child, model) {
return Text(
'${model.counter}, Api URL: ${AppConfig.of(context).apiURL}',
);
},
),
],
),
),
// 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),
);
},
),
);
}
}
from scoped_model.
Brian,
Thank you for the quick response. I've tried again with this wrapping of my widgets to access the proper context but I've still come up short.
I will detail my code below...
I have an AppConfig class that will contain an API URL that will differ on each build. From my knowledge, creating this inherited widget subclass is supposed to allow me to reach in and get the .apiURL string value after using the static function; AppConfig.of(context).apiURL
class AppConfig extends InheritedWidget {
final String apiURL;
AppConfig({
@required this.apiURL,
@required Widget child,
}) : super(child: child);
static AppConfig of(BuildContext context) {
return context.inheritFromWidgetOfExactType(AppConfig);
}
@OverRide
bool updateShouldNotify(InheritedWidget oldWidget) => false;
}
Here is my main_dev.dart file that I run when I test the app.
void main() {
var configuredApp = AppConfig(
apiURL: 'https://dev-api.example.com/',
buildIdentifier: BuildIdentifier.DEV,
buildName: 'Development',
child: MyApp(),
);
runApp(configuredApp);
}
Here is my lib/main.dart file with the routing AND the Scoped Model
class MyApp extends StatefulWidget {
@OverRide
State createState() {
return _MyAppState();
}
}
class _MyAppState extends State {
final MainModel _model = MainModel();
@OverRide
Widget build(BuildContext context) {
return ScopedModel(
child: MaterialApp(
routes: {
'/': (BuildContext context) => MainScreen(_model),
},
theme: getThemeData(context),
title: 'My App',
),
model: _model,
);
}
}
This is where I'm having my context give me questionable behavior, where I'm unable to use the context to then use my AppConfig's static function on to fetch my build's API URL.
class MainScreen extends StatefulWidget {
final MainModel model;
MainScreen(this.model);
@OverRide
State createState() {
return _MainScreenState();
}
}
1. This way about it doesn't work...
class _MainScreenState extends State {
@OverRide
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppConfig.of(context).apiURL), // The getter 'apiURL' was called on null, and the whole screen is a sea of red.
),
body: _buildGridView(context),
);
}
}
2. This new way wrapping the context in a new class widget doesn't work either.
class _MainScreenState extends State {
@OverRide
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: BrowseTitle(),
),
body: _buildGridView(context),
);
}
}
class BrowseTitle extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
var appConfig = AppConfig.of(context);
return Text(appConfig.apiURL); // The getter 'apiURL' was called on null, but only the app bar title widget comes out as a red box
}
}
Thanks for taking a look at this, Brian.
from scoped_model.
Related Issues (20)
- Some widget don't refresh after calling notifyListener in flutter 1.22.1
- bloc model value fetch in init function not working
- can't run
- can't run
- Error: Could not find the correct ScopedModel.
- Testing when using scopedModelDescendant HOT 2
- 单独抽离一个方法 如何修改值?
- 不继承 ScopedModelDescendant() 如何修改值?
- void initState() 方法里如何修改值?
- Not Working error
- Target of URI doesn't exist: 'package:scoped_model/scoped_model.dart'.
- Publish null safe stable version
- Error: Could not find the correct ScopedModel. To fix, please: * Provide types to ScopedModel<MyModel> * Provide types to ScopedModelDescendant<MyModel> * Provide types to ScopedModel.of<MyModel>() * Always use package imports. Ex: `import 'package:my_app/my_model.dart'; If none of these solutions work, please file a bug at:
- Exception has occurred. ScopedModelError (Error: Could not find the correct ScopedModel.
- kindly update
- scoped_model issues HOT 6
- Scoped Model - not working after go back to previous page
- Model notifyListeners closes EndDrawer
- ScopedModel
- scoped_model.of() issue HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from scoped_model.