Following on from Unhandled Exception: type '_DropdownRouteResult<int>' is not a subtype of type 'int?' when returning value from Navigator.pop() as I still haven't resolved the issue.
I have a DropdownFormField
which I am dynamically populating from a db via a Provider
. I would like to add a DropdownMenuItem
which, when selected, pushes a new route (for inserting a new record into the db).
The route returns the id of the newly-inserted db record when popped, and I would like to set the new value as the value of the DropdownFormField
.
Implementing the new item with a TextButton
child and pushing in the buttons' onPressed
results in expected push/pop behaviour, but is styled inconsistently from the "normal" items, and does not close the dropdown (which makes sense as the button is pressed, but the DropdownMenuItem
is not tapped). Tapping outside the dropdown after popping reveals that the dropdown's value is updated correctly.
DropdownMenuItem<int>(child: TextButton(
onPressed: () async {
final int newValue = await Navigator.push(context, AddNewTeaProducerRoute());
setState(() {
_selectedValue = newValue;
});
},
child: Text('Add New Manufacturer')));
Implementing the new item with a Text
child and pushing in the DropdownMenuItem
's onTap
(which seems like the correct approach) results in an immediate attempt to return the value, disrespecting the asynchronous nature of the onTap
and resulting in the exception from my previous question. Breakpoint debugging without specifying the type of newValue
shows that it is immediately assigned the Future
/_DropdownRouteResult<int>
, rather than awaiting its returned int
.
DropdownMenuItem<int>(
onTap: () async {
final int newValue = await Navigator.push(context, AddNewTeaProducerRoute());
setState(() {
_selectedValue = newValue;
});
},
child: const Text('Add New Manufacturer'));
I have no idea why await
is being respected in TextButton.onPressed
but not in DropdownMenuItem.onTap
CodePudding user response:
I don't know if it's the right way, since it relies on null
as a placeholder value and I can't see how you'd easily scale it beyond a single DropdownMenuItem with special behaviour (as unlikely as it seems that you'd want to) but after reading this for the third time I finally grokked a solution - return null as the value, and perform navigation/assignment in the DropdownButtonFormField
's onChanged
final brokenAddNewTeaProducerButton = DropdownMenuItem<int>(
value: null,
child: const Text('Add New Manufacturer'));
return DropdownButtonFormField<int?>(
value: _selectedValue,
items: [brokenAddNewTeaProducerButton] teaProducerListItems,
onChanged: (value) async {
if (value == null) {
final newTeaProducerId = await Navigator.push(context, AddNewTeaProducerRoute());
setState(() {
_selectedValue = newTeaProducerId;
});
} else {
setState(() {
_selectedValue = value;
});
}
},
hint: Text('Select a manufacturer'),
);
}
CodePudding user response:
**You can try this statfulBuilder**
StatefulBuilder(builder: (context,state){
return DropdownMenuItem<int>(child: TextButton(
onPressed: () async {
var newValue = await Navigator.push(context,
AddNewTeaProducerRoute());
state(() {
_selectedValue = newValue;
});
},
child: Text('Add New Manufacturer')));
}),