How to Retrieve value from DropdownFormField? - flutter

I used dropdownformfield to get the gender of user in the sign up page, I created the widget in other class, I wanna know how can I control the field or retrieve the value when it changes because it doesnt have a controller unlike textformfield.

I would suggest adding an onChanged callback that can be passed into the constructor of the class containing the dropdown field.
class DropdownField extends StatelessWidget {
final Function(dynamic) onChanged;
DropdownField({#required this.onChanged});
#override
Widget build(BuildContext context) {
return DropdownButtonFormField(
onChanged: this.onChanged,
);
}
}
Then when you instantiate the class, have it manipulate something on callback.
class _OtherClassState extends State<OtherClass> {
var _selectedItem;
#override
Widget build(BuildContext context) {
return DropdownField(
onChanged: (newItem) => setState(() => this._selectedItem = newItem),
);
}
}

Related

Flutter detect when value passed to the statefull widget changes

I have a statefull widget where am passing an integer to. I would like to execute a method when the value passed to the widget changes
class Test extends StatefulWidget {
final String item;
const Test({
Key? key,
required this.item,
}) : super(key: key);
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
List<String> hh = [];
#override
void initState() {
super.initState();
print("init state value is ${widget.item}");
}
#override
Widget build(BuildContext context) {
return Container();
}
void getDataItems() {
print("value passed is ${widget.item}");
setState(() {
hh = [widget.item];
});
}
}
So on the above i would like to detect when the value of string item passed to the widget changes and call the method getDataItems which will later update the list hh.
How can i detect when the value passed statefull widget has changed?
You can check the useEffect, which is based on the React hook useEffect.
Or you can hardcode it.
Create other integer: late int lastCalledInteger;
And check this in the build:
#override
Widget build(BuildContext context) {
if(lastCalledInteger != integer) {
getDataItems();
lastCalledInteger = integer;
}
return Container();
}
You can simply override didUpdateWidget on State to be informed of every change of passed in arguments. If you have multiple arguments you of course need to change what changed. For this didUpdateWidget provides you with the oldWidget as only parameter.
From the documentation:
Called whenever the widget configuration changes.
[...]
Override this method to respond when the widget changes (e.g., to
start implicit animations).

How can I Insert another Widget in place of another when one is pressed?

I am an entry level flutter developer and I've been stuck for a while on this problem, I've tried different things
I am try to make the 'Note Title' (that particular widget), pop out
The app_issue description
then this should show instead
desired result
The two different content under the "My Notes" tab are two Stateful Widgets and the "My Notes" tab is another Stateful Widget on its own
I've tried using a function but it doesn't work
enum MyNoteContent {
staticNote,
dynamicNote,
}
MyNoteContent selectedContent = MyNoteContent.staticNote;
Widget updateMyNotes() {
if (selectedContent == MyNoteContent.staticNote) {
return MyNoteStatic();
} else {
return MyNoteDynamic();
}
}
and then i call the function in the MyNotes Widget
class _MyNotesTabState extends State<MyNotesTab> {
#override
Widget build(BuildContext context) {
return updateMyNotes();
}
}
I trying to update the value in the first content that is shown (in its own Widget), so that when it is pressed, it should change
class _MyNoteStaticState extends State<MyNoteStatic> {
#override
Widget build(BuildContext context) {
return Container(
child: RawMaterialButton(
onPressed: () {
setState(() {
selectedContent = MyNoteContent.dynamicNote;
updateMyNotes();
});
},
but it does not work
Code to Reproduce the Problem
The issue here is that the setState you're calling is for the _MyNoteStaticState class. This means it will only rebuild the MyNoteStatic widget. But in order for the page to change you need to rebuild its parent _MyNotesTabState. So you need to call the setState method of _MyNotesTabState which can be done by passing a callback down from _MyNotesTabState to _MyNoteStaticState.
First, move updateMyNotes & selectedContent into the _MyNotesTabState class since that's the only place they're needed.
Make a new function that rebuilds _MyNotesTabState and changes selectedContent in _MyNotesTabState.
void changeNote() {
setState(() {
selectedContent = MyNoteContent.dynamicNote;
});
}
Pass it down to MyNoteStatic
Widget updateMyNotes() {
if (selectedContent == MyNoteContent.staticNote) {
return MyNoteStatic(changeNote);
} else {
return MyNoteDynamic();
}
}
and modify MyNoteStatic to accept this callback as a parameter
class MyNoteStatic extends StatefulWidget {
final VoidCallback callback;
MyNoteStatic(this.callback);
#override
_MyNoteStaticState createState() => _MyNoteStaticState();
}
Then pass this callback to your button instead of what you currently have:
child: RawMaterialButton(
onPressed: widget.callback,
)
Full relevant code incorporating the above changes:
enum MyNoteContent {
staticNote,
dynamicNote,
}
class MyNotesTab extends StatefulWidget {
#override
_MyNotesTabState createState() => _MyNotesTabState();
}
class _MyNotesTabState extends State<MyNotesTab> {
MyNoteContent selectedContent = MyNoteContent.staticNote;
#override
Widget build(BuildContext context) {
return updateMyNotes();
}
Widget updateMyNotes() {
if (selectedContent == MyNoteContent.staticNote) {
return MyNoteStatic(changeNote);
} else {
return MyNoteDynamic();
}
}
void changeNote() {
setState(() {
selectedContent = MyNoteContent.dynamicNote;
});
}
}
//Static Note
class MyNoteStatic extends StatefulWidget {
final VoidCallback callback;
MyNoteStatic(this.callback);
#override
_MyNoteStaticState createState() => _MyNoteStaticState();
}
class _MyNoteStaticState extends State<MyNoteStatic> {
#override
Widget build(BuildContext context) {
return Container(
child: RawMaterialButton(
onPressed: widget.callback,
...

Initialize StateProvider in Widget

I just want initialize provider only one time with widget param. For some reason I can't use .family. I'm not sure if this is the right way. Can you check this? Thank you.
StateProvider<String> valueStateProvider;
class Widget extends HookWidget {
final String value;
Widget({#required this.value}) {
valueStateProvider = StateProvider<String>((ref) => this.value);
}
}
Finally I found the right way to do this. There is special provider type for this situation. ScopedProvider.
final scopedProvider = ScopedProvider<String>((_) => throw UnimplementedError());
class Widget extends HookWidget {
Widget({#required this.value});
final String value;
#override
Widget build(BuildContext context) {
return ProviderScope(
overrides: [scopedProvider.overrideWithValue(this.value)],
child: AnotherWidget()
);
}
}
So you can use scopedProvider in AnotherWidget. Yay!

Custom dropdown widget in Flutter how to implement setState

I implemented a custom DropdownButton widget, but I don't know how to implement it's setState. I would like to pass items and selectedItem to the widget, and let it to handle it's own state. And retrieve selected item when needed by myDropdownButton.selectedItem. How I could implement it?
class MyDropdownButton extends StatefulWidget {
final String selected;
final List<MyDropdownItem> items;
MyDropdownButton({Key key, this.selected, this.items})
: super(key: key);
#override
_MyDropdownButtonState createState() => _MyDropdownButtonState();
}
class _MyDropdownButtonState extends State<MyDropdownButton> {
Widget build(BuildContext context) {
return DropdownButtonFormField(
value: widget.selected,
onChanged: (String value) {
widget.selected = value;
},
But the selected is final and cannot be modified. How to implement it?
Thank you!
There are two questions here:
Updating the widget, using setState.
Passing the value back to the widget that is using the Dropdown with a callback. Medium Article on callbacks
Firstly to have the dropdown update, you need to call a setstate on the value change. But first, you'll need to receive the value passed, usually this is done in initstate.
Second, you need to use a callback function. The class that calls this widget/class can then receive and process that value
class MyDropdownButton extends StatefulWidget {
final String selected;
final List<MyDropdownItem> items;
final Function(String) valueReturned; //callback function
MyDropdownButton({Key key, this.selected, this.items, this.valueReturned})
: super(key: key);
#override
_MyDropdownButtonState createState() => _MyDropdownButtonState();
}
class _MyDropdownButtonState extends State<MyDropdownButton> {
String sel;
#override
void initState() {
super.initState();
sel = widget.selected; //get the value passed
}
Widget build(BuildContext context) {
return DropdownButtonFormField(
value: sel
onChanged: (String value) {
setState() {
sel = value;
widget.valueReturned(value); //this will trigger the callback function
},
}
In the code that calls the widget, you will need to listen to and handle the response.
Container(
child: MyDropdownButton(items: items, selected: selected, valueReturned: _handleValueReturned))
_handleValueReturned(String value) {
thingToUpdate = value;
}
Define a local variable and initialize it in initState():
String _selected;
#override
void initState() {
super.initState();
_selected = widget.selected;
}
use setState to update your local variable as the selection changes:
onChanged: (String value) {
setState(() {_selected = value;})
}
To retrieve the value, define a getter in your class:
String get selectedItem => _selected;
You can then access the selected item using myDropdownButton.selectedItem.
For more detailed explanation on implicit and explicit getters/setters see How do getters and setters change properties in Dart?

How to set TextFormField dynamically?

I am using flutter and I want to set text (String value) in TextFormField dynamically, means set value over press of a button.
use TextEditingController. Then assign it to the TextFormField then make use of the controller to assign the new data from wherever you want. If you want initial data assign it some value in the initState() function also use it on a stateful widget.
_textEditingController.text = "1";
You can make use of a StatefulWidget to adjust the initialValue property of your TextFormField.
class TextFieldChanger extends StatefulWidget {
#override
_TextFieldChangerState createState() => _TextFieldChangerState();
}
class _TextFieldChangerState extends State<TextFieldChanger> {
String presetText;
void _onPressed() {
setState(() {
presetText = 'updated text';
});
}
#override
Widget build(BuildContext context) => Column(children: [
TextFormField(initialValue: presetText),
RawMaterialButton(onPressed: _onPressed),
]);
}
In setState, I am assigning a new value to presetText and build will be called (with the updated initialValue) because of setState.