How To Add States Functionality Inside Flutter showDialog() Function

How To Add States Functionality Inside Flutter showDialog() Function

When I add a CheckBox() widget inside the content of the AlertDialog widget inside of the showDialog() function in the TextButton widget onPressed() function, I found that the checkbox did not rebuild when I click on it.

The checkbox did not rebuild because the showDialog() has its own build context. Even when I am using the StatefulWidget, the checkbox did not response and rebuild as expected when I click on it.

So, I wrap the AlertDialog widget using a StatefulBuilder widget and move the Boolean variable for the checkbox value above it and it solved the checkbox issue.

Here are the steps:

Before

import 'package:flutter/material.dart';

import '../../constants/colors.dart';
import '../../constants/styles.dart';

class DialogSendFeedback extends StatefulWidget {
  const DialogSendFeedback({super.key});

  @override
  State<DialogSendFeedback> createState() => _DialogSendFeedbackState();
}

class _DialogSendFeedbackState extends State<DialogSendFeedback> {
  final TextEditingController feedback = TextEditingController();
  final FocusNode feedbackFocus = FocusNode();

  bool agree = false;

  @override
  void dispose() {
    feedback.dispose();
    feedbackFocus.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TextButton.icon(
        onPressed: () {
          showDialog(
            context: context,
            builder: (context) {
              return AlertDialog(
                title: const Text('Send the project to Engineers'),
                content: SizedBox(
                  width: 600,
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      const Row(
                        children: [
                          Expanded(
                              child: Text(
                            'We are sorry that you encountered some issues. To assist us in investigating the matter, kindly provide the details of the project.',
                            maxLines: 3,
                          ))
                        ],
                      ),
                      const SizedBox(
                        height: 16,
                      ),
                      Expanded(
                        child: Row(
                          children: [
                            Expanded(
                                child: TextFormField(
                              controller: feedback,
                              focusNode: feedbackFocus,
                              autofocus: true,
                              keyboardType: TextInputType.multiline,
                              textInputAction: TextInputAction.newline,
                              maxLines: 100,
                              decoration: const InputDecoration(
                                  alignLabelWithHint: true,
                                  contentPadding: EdgeInsets.all(8),
                                  label: Text('Issue detail'),
                                  hintText:
                                      'Describe the issue as detailed as possible.'),
                            ))
                          ],
                        ),
                      ),
                      const SizedBox(
                        height: 16,
                      ),
                      Row(
                        children: [
                          Checkbox(
                              checkColor: whiteColor,
                              fillColor: WidgetStateProperty.resolveWith(
                                  (states) => darkTealColor),
                              value: agree,
                              onChanged: (bool? value) {
                                setState(() {
                                  agree = value!;
                                });
                              }),
                          const SizedBox(
                            width: 8,
                          ),
                          const Expanded(
                            child: Text(
                              'I agree to send these project details to Schletter Engineering for their investigation.',
                              maxLines: 3,
                            ),
                          )
                        ],
                      )
                    ],
                  ),
                ),
                actions: [
                  TextButton(
                      style: defaultPrimaryButtonStyle,
                      onPressed: () {
                        Navigator.of(context).pop(false);
                      },
                      child: const Text(
                        'Do not send',
                        style: buttonTextWhite,
                      )),
                  TextButton(
                      style: defaultSecondaryButtonStyle,
                      onPressed: agree == true
                          ? () {
                              Navigator.of(context).pop(true);
                            }
                          : null,
                      child: Text(
                        'Send',
                        style: defaultSecondaryButtonTextStyle,
                      ))
                ],
              );
            },
          ).then((value) {
            if (value == true) {
              // make a call to backend API to save the feedback
            }
          });
        },
        icon: const Icon(
          Icons.help_outline_rounded,
          color: whiteColor,
        ),
        label: Text(
          'Ask for help',
          style: defaultPrimaryButtonTextStyle,
        ));
  }
}

After

import 'package:flutter/material.dart';

import '../../constants/colors.dart';
import '../../constants/styles.dart';

class DialogSendFeedback extends StatefulWidget {
  const DialogSendFeedback({super.key});

  @override
  State<DialogSendFeedback> createState() => _DialogSendFeedbackState();
}

class _DialogSendFeedbackState extends State<DialogSendFeedback> {
  final TextEditingController feedback = TextEditingController();
  final FocusNode feedbackFocus = FocusNode();

  @override
  void dispose() {
    feedback.dispose();
    feedbackFocus.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TextButton.icon(
        onPressed: () {
          showDialog(
            context: context,
            builder: (context) {
              bool agree = false; // <- here
              return StatefulBuilder( // <- here
                builder: (context, setState) => AlertDialog(
                  title: const Text('Send the project to Engineers'),
                  content: SizedBox(
                    width: 600,
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        const Row(
                          children: [
                            Expanded(
                                child: Text(
                              'We are sorry that you encountered some issues. To assist us in investigating the matter, kindly provide the details of the project.',
                              maxLines: 3,
                            ))
                          ],
                        ),
                        const SizedBox(
                          height: 16,
                        ),
                        Expanded(
                          child: Row(
                            children: [
                              Expanded(
                                  child: TextFormField(
                                controller: feedback,
                                focusNode: feedbackFocus,
                                autofocus: true,
                                keyboardType: TextInputType.multiline,
                                textInputAction: TextInputAction.newline,
                                maxLines: 100,
                                decoration: const InputDecoration(
                                    alignLabelWithHint: true,
                                    contentPadding: EdgeInsets.all(8),
                                    label: Text('Issue detail'),
                                    hintText:
                                        'Describe the issue as detailed as possible.'),
                              ))
                            ],
                          ),
                        ),
                        const SizedBox(
                          height: 16,
                        ),
                        Row(
                          children: [
                            Checkbox(
                                checkColor: whiteColor,
                                fillColor: WidgetStateProperty.resolveWith(
                                    (states) => darkTealColor),
                                value: agree,
                                onChanged: (bool? value) {
                                  setState(() {
                                    agree = value!;
                                  });
                                }),
                            const SizedBox(
                              width: 8,
                            ),
                            const Expanded(
                              child: Text(
                                'I agree to send these project details to Schletter Engineering for their investigation.',
                                maxLines: 3,
                              ),
                            )
                          ],
                        )
                      ],
                    ),
                  ),
                  actions: [
                    TextButton(
                        style: defaultPrimaryButtonStyle,
                        onPressed: () {
                          Navigator.of(context).pop(false);
                        },
                        child: const Text(
                          'Do not send',
                          style: buttonTextWhite,
                        )),
                    TextButton(
                        style: defaultSecondaryButtonStyle,
                        onPressed: agree == true
                            ? () {
                                Navigator.of(context).pop(true);
                              }
                            : null,
                        child: Text(
                          'Send',
                          style: defaultSecondaryButtonTextStyle,
                        ))
                  ],
                ),
              );
            },
          ).then((value) {
            if (value == true) {
              // make a call to backend API to save the feedback
            }
          });
        },
        icon: const Icon(
          Icons.help_outline_rounded,
          color: whiteColor,
        ),
        label: Text(
          'Ask for help',
          style: defaultPrimaryButtonTextStyle,
        ));
  }
}

That’s it. Hopefully you found this post useful. Happy coding!