How to pass arguments to a widget using a variable:
tldr; We have to turn our thinking on its head a bit. Data can be
passed to the called widget when you navigate to it by using final
arguments with default values in the destination widget. Using an
optional function you can get data back from the 'child' (destination)
widget.
In the destination stateful widget you create a final variable;
final int boxIndex;
In the destination constructor give your final variable a constant default value
DestinationClassConstructor({Key? key, this.boxIndex = -1}): super(key: key);
You can add methods to the stateful widget class that use the value in some significant way:
e.g.
bool isEditing() {
return this.boxIndex != -1;
}
In the source widget that calls the destination widget, you can pass in a value other than the default.
DestinationClassConstructor(boxIndex: 123),
In the destination widgets state content class you could use the value directly or call the method above:
e.g.
widget.isEditing()
widget.boxIndex,
The real power of this method happens when you decide that you can
pass Functions as parameters:
e.g.
In your destination stateful widget create the nullable function call with its constructor argument:
final Function()? destinationWidgetTapped;
DestinationClassConstructor({Key? key, this.destinationWidgetTapped}): super(key: key);
Note: In this case the function variable is assigned a default value
of null.
Somewhere in your destination content state widget call the function:
if (widget.destinationTapped != null) widget.destinationWidgetTapped!();
Then in your source widget make the call as follows:
DestinationClassConstructor(destinationWidgetTapped: () {
print('this code from the source widget executes after the child widget event is invoked');
Navigator.of(context).pop(); //pop the child widget
},
Which is fine and very useful when you consider that you can also pass back a value along with the function call.
final Function(String)? destinationWidgetTapped;
DestinationClassConstructor({Key? key, this.destinationWidgetTapped}): super(key: key);
Somewhere in your destination content state widget call the function:
if (widget.destinationTapped != null) widget.destinationWidgetTapped!('Hello from the Destination Content State Widget');
Then you can receive data like this:
DestinationClassConstructor(destinationWidgetTapped: (value) {
print('Data is passed from the destination widget with a string value of : $value');
Navigator.of(context).pop();
},
Nota Bene:
Function(String)
can also be written as ValueChanged<String>
We can further extrapolate that any object may be passed:
Function(Object?)
written as ValueChanged<Object?>
And the argument might be better written as:
final ValueChanged<Object?>? onValueChanged;
DestinationClassConstructor({Key? key, this.onValueChanged}): super(key: key);
Which would allow one to send any data object, array, json, map,
string, int, bool, etc. while maintaining access to a completion
handler so that one could access the variable data in both directions.