I'm using Provider
to provide some data to my screen and an alert dialog. Knowing that AlertDialog
is scooped outside the widget tree, I added a ChangeNotifierProvider
as a wrapper widget of that dialog. But still, the UI is not changing even though I made sure the values are updated in the provider state.
Code Snippet:
showTextDialog(BuildContext context) {
final myModel = Provider.of<ServicesProvider>(context, listen: false);
return showDialog(
context: context,
builder: (_) => ChangeNotifierProvider.value(
value: myModel,
child: AlertDialog(
content: IntrinsicHeight(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
Radio(
value: '0',
groupValue: myModel.paymentMethod,
onChanged: (value) => myModel.setPaymentMethod('0'),
activeColor: ColorResources.PRIMARY_COLOR,
toggleable: true,
),
SizedBox(width: responsiveWidth(5)),
Text("Radio Button 1"),
],
),
SizedBox(height: responsiveHeight(10)),
Row(
children: [
Radio(
value: '1',
groupValue: myModel.paymentMethod,
onChanged: (value) => myModel.setPaymentMethod('1'),
activeColor: ColorResources.PRIMARY_COLOR,
toggleable: true,
),
SizedBox(width: responsiveWidth(5)),
Flexible(child: Text("Radio Button 2")),
],
),
],
),
),
),
),
);
}
Thanks for your help.
CodePudding user response:
The main idea behind your problem is that you do not subscribe to the changes of your ServicesProvider
. You can replace Provider.of<ServicesProvider>(context, listen: false);
with context.read<ServicesProvider>();
that is a more concise syntax using extension methods.
Based on the Provider documentation:
context.read<T>(), which returns T without listening to it. <...> It's worth noting that context.read<T>() won't make a widget rebuild when the value changes and it cannot be called inside StatelessWidget.build/State.build. On the other hand, it can be freely called outside of these methods.
What you have done already with final myModel = Provider.of<ServicesProvider>(context, listen: false);
is that you only retrieved the reference to ServicesProvider
. However, this way you do not subscribe to the changes inside the model - this is exactly what the documentation explains.
To resolve this, you can move the AlertDialog
into a separate widget, e.g. MyDialog
. There is a practical reason - it's just easier to understand that now you are not using the same context and you should access the re-provided ServicesProvider
model. Now, by using context.watch<ServicesProvider>()
(you could use the Consumer
widget as well if you would like to), you can subscribe to the changes of your model. Thus, when there is a change for the paymentMethod
value inside the model (you can do it by calling the setPaymentMethod()
method on model), it triggers UI rebuild (notifyListeners()
does its work) and you get the expected output.
You could find the recreated and resolved issue here.