This is problably sthg simple, I would like to pop a widget and to pass different parameters, here is what I have :
class MyScreen extends StatefulWidget {
final String param0;
final String param1;
final String param2;
MyScreen(param0,param1,param2);
#override
MyState createState() => new MyScreenState();
}
...
I would like to go back to this widget passing parameters, something like this :
Navigator.pop(context, "NewParam0", "NewParam1", "NewParam2");
but it doesn't work.
I can pop with 1 parameter and the context, but it doesn't work with multiple parameters,
Any idea?
Yep, the solution is simple! The way I've dealt with this is by popping an object. For instance, a Map<String, String>:
Navigator.pop(context,
{"NewParam0": "param0value", "NewParam1": "param1value", "NewParam2": "param2value"}
);
(see https://api.flutter.dev/flutter/widgets/Navigator/pop.html and https://flutter.dev/docs/cookbook/navigation/returning-data)
You could also make a lightweight class to pop that will populate default params, etc. if you have a lot of complexity to pass back and forth, though at that point, I might try to rework my state management a little bit.
Related
A class Object passing from First Screen to the second Screen While on the second screen when the object changed its value, it's also changing the value on first screen.
Code of First Screen. (widget.templateModel is an object class that i am passing to the second screen)
Navigator.push(context,MaterialPageRoute(builder: (context) =>
EditEmojiTextTemplateScreen(templateModel: widget.templateModel,));
Code of Second Screen (On the second screen i am receiving the object and when i am changing the value of widget.templateModel it also changing the value on the first screen for a simple understandable code below i changed the value in initState while in the gif i am changing value in TextFormField)
class EditEmojiTextTemplateScreen extends StatefulWidget {
final TemplateModel templateModel;
EditEmojiTextTemplateScreen({
Key? key,
required this.templateModel,
}) : super(key: key);
#override
State<EditEmojiTextTemplateScreen> createState() =>
_EditEmojiTextTemplateScreenState();
}
class _EditEmojiTextTemplateScreenState
extends State<EditEmojiTextTemplateScreen> {
final SharedPreferences sharedPreferences = sl();
var txtNameController = TextEditingController();
var txtColorController = TextEditingController();
_EditEmojiTextTemplateScreenState();
#override
void initState() {
widget.templateModel.emoji[0].titleTwo = "kdfff"; //here i am changing the value and it also changing the value on first screen and i dont want this behavior of this object
super.initState();
}
Note: This is happening because of widget variable as mentioned in the documentation but i don't know how to prevent this behavior.
package:flutter/src/widgets/framework.dart
The current configuration.
A [State] object's configuration is the corresponding [StatefulWidget]
instance. This property is initialized by the framework before calling
[initState]. If the parent updates this location in the tree to a new
widget with the same [runtimeType] and [Widget.key] as the current
configuration, the framework will update this property to refer to the
new widget and then call [didUpdateWidget], passing the old
configuration as an argument.
Now I see what you are trying to do.
You could initialize a NEW istance of TemplateModel in the InitState of the second screen.
Then, set the new object's properties like this (or write a cleaner method to do that):
newObject.property1 = oldObject.property1;
newObject.property2 = oldObject.property2;
...
Once the user presses the save button, change oldObject's properties again, so that the first page updates.
You might want to take a look at state management to better understand how to approach this kind of problems.
As the other answer suggests, take a look at state management solutions.
Also keep the models immutable by creating them with final fields. Then to modify, create new instances via copyWith()
Please update you code after navigation.then method
template = snapshot.data;
I have an unusual use case where I'd like to add a getter to a StatefulWidget class that accesses its State instance. Something like this:
class Foo extends StatefulWidget {
Foo({super.key});
int get bar => SomethingThatGetsFooState.bar;
#override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> {
int bar = 42;
#override
Widget build(BuildContext context) {
return Container();
}
}
Does SomethingThatGetsFooState exist?
I wonder, if your approach is the right way.
Flutter's way isn't 'Ask something about its state'
Flutter is much more like this: 'The consumer of a Widget passes something to another Widget, which the other Widget e.g. calls in case of certain situations (e.g. value change).'
Approach 1
You map pass a Callback Function to Foo and pass that along to _FooState.
If something special happens inside _FooState, you may call the callback and thus pass some value back to the provider of the Callback.
Approach 2
Probably use a state management solution like Flutter Redux. Using Flutter Redux, you establish a state store somewhere at the top of the widget tree, e.g. in MaterialApp.
Then you subscribe to the store at certain other locations, where dependent widgets exist, which need to update accordingly.
In one project I created certain Action classes, which I send to certain so called reducers of those states, to perform a change on the state:
StoreProvider.of<EModel>(context).dispatch( SaveToFileAction())
This call finds the relevant EModel state and asks it to perform the SaveToFileAction().
This way, a calling Widget not even needs to know, who is responsible for the Action.
The responsible Widget can even be moved around the widget tree - and the application still works. The initiator of SaveToFileAction() and the receiver are decoupled. The receiver you told a coordination 'Tell me, if someone tried to ask me for something.'
Could your provide some further details? Describe the usage pattern?
#SteAp is correct for suggesting there's a code smell in my OP. Typically there's no need to access State thru its StatefulWidget. But as I responded to his post, I'm fleshing out the first pass at a state management package, so it's an unusual case. Once I get it working, I'll revisit.
Below worked without Flutter complaining.
class _IntHolder {
int value;
}
class Foo extends StatefulWidget {
Foo({super.key});
final _intHolder = _IntHolder();
int get bar => _intHolder.value;
#override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> {
int value = 42;
#override
Widget build(BuildContext context) {
widget._intHolder.value = value;
return Container();
}
}
How to get data from previous page when using stateful String link.
Is it possible to get string from another file in stateful?
I need to get the string from another file b into the stateful of file a. In case of stateless this was possible, but in stateful it is not possible.
Is there a way to solve this?
I hate to disagree but using global variables in this situation when you can fix your problem easily is not wise although it works and it is very easy.
if you want to send data to another page via pushing a new page you can always use that newPage Constructor
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BalancePage(
items: "item",
),
),
);
New Page
class BalancePage extends StatefulWidget {
String? items;
BalancePage({
this.items,
});
#override
_BalancePageState createState() => _BalancePageState();
}
if you want to take data from another class you can set a getter
class newVal(){
String val ="ss";
String getVal(){
return val;
}
}
and you can call it anywhere like this
String ss = newVal().getVal;
I am building a Stateful Widget in Flutter, and as such, there is a requirement for all arguments passed in the constructor to be final (since Stateful widgets are marked with the #immutable annotation).
Thing is, I want to have two different constructors for my widget and to exclude some of the members of the Stateful widget, depending on the constructor used. I have to stress, that I do not want these arguments to be optional, but mandatory.
For example,
class MyWidget extends StatefulWidget {
MyWidget.first({this.firstArgument}};
MyWidget.second({this.secondArgument});
final int firstArgument;
final String secondArgument;
#override
MyWidget createState() => MyWidgetState();
}
When I write this, I get a compiler error, telling me that:
All final variables must be initialized, but 'firstArgument' isn't.
The same goes for the second member variable.
How can I overcome this?
I can't move firstArgument and secondArgument to the state of MyWidget, since I want them to be initialized in the constructor(s) and also because they should not be changed.
I can't mark them as not final since then I will get a compiler warning and also break the Stateful widget paradigm.
Is there a different approach I should use?
Thing is, I want to have two different constructors for my widget and to exclude some of the members of the Stateful widget, depending on the constructor used. I have to stress, that I do not want these arguments to be optional, but mandatory.
If you don't want them to be optional, you need to mark them as required:
MyWidget.first({required this.firstArgument}};
MyWidget.second({required this.secondArgument});
(If you don't have null-safety enabled, you will instead need to use the weaker #required annotation from package:meta.)
My understanding is that you want firstArgument and secondArgument to be required for MyWidget.first and MyWidget.second respectively but that they are not intended to be required together (that is, only one should be set).
You could fix this by explicitly initializing both values in the constructors:
MyWidget.first({required this.firstArgument}} : secondArgument = null;
MyWidget.second({required this.secondArgument}): firstArgument = null;
If you have null-safety enabled, you also would need to make your members nullable:
final int? firstArgument;
final String? secondArgument;
Maybe factory constructors would help?
class MyWidget extends StatefulWidget {
MyWidget._({this.firstArgument, this.secondArgument}};
factory MyWidget.first({#required int first})=>MyWidget._(firstArgument: first, );
factory MyWidget.second({#required String second})=>MyWidget._(secondArgument: second, );
final int firstArgument;
final String secondArgument;
#override
MyWidget createState() => MyWidgetState();
}
This way, you'll only be able to build this widget using these constructors (since the class constructor is private) and when you call MyWidget.first the value for secondArgument for the widget will be null, and the same applies when you use MyWidget.second with firstArgument
I have a StatelessWidget that uses a ScopedModel to store its data. The widget basically presents a list of checkboxes and some buttons to save the state of the checked boxes.
Now I want to keep track of if the user has altered any of the checkboxes, i.e. checked/unchecked them since the widget was displayed. So I added something like this:
class MyCheckboxScreen extends StatelessWidget{
bool _hasBeenModified = false;
void _itemCheckedChange(bool checked, MyModel model){
_hasBeenModified = true;
// Code to change the model here
}
void _onCloseButton(){
if( _hasBeenModified ){
// Show a warning that there are modifications that will not be be saved
}
}
void _onSaveButton(Context context, MyModel model){
model.save();
Navigator.of(context).pop();
}
}
This seems to work, but my StatelessWidget now contains its own state.
The state isn't used to update the UI and redraw anything, it's only used to check if there are modifications to any checkbox when pressing the "Close" button.
Is it safe for a StatelessWidget to have this kind of internal state? Or could it be a problem? For example, could the widget be recreated unexpectedly, and the internal state lost?
I don't find the documentation to be very clear on this, it just says
For compositions that can change dynamically, e.g. due to having an internal clock-driven state, or depending on some system state, consider using StatefulWidget.
But this sounds like it only applies to state that affects the UI and requires rebuilding the widget.
Yes, a StatelessWidget can have mutable variables (your code compiles) but that's wrong.
A widget that does not require mutable state
This is taken from the documentation. Even if you have a single non-final variable, it means that something can actually be changed in your widget. It's not an immutable class. Ideally, you should use StatelessWidgets like this:
class MyWidget extends StatelessWidget {
final int a;
final String b;
const MyWidget(this.a, this.b);
}
Or something similar such as
class MyWidget extends StatelessWidget {
const MyWidget();
}
When you have non final variables, use a StatefulWidget. Your class has to clearly be a StatefulWidget:
// This is not final. It can be changed (and you will change it)
// so using the stateless way is wrong
bool _hasBeenModified = false;
void _itemCheckedChange(bool checked, MyModel model){
_hasBeenModified = true;
}
The UI doesn't matter actually because here's a matter of variables and mutability. Something is changing (bool _hasBeenModified) so it cannot be a StatelessWidget because it has to be used in all those cases where the state is immutable.
Are there any reasons why you don't use a stateful widget? Stateless widgets aren't intended to be used that way.. And without any benefits, I don’t understand why you overcomplicate things..