skip to Main Content

I made a delete button that pops up a dialog and makes you record the reason for the delete. I only want the submit button enabled if the user enters a reason. Here is what I have for that widget:

  class _DeleteCrewMemberWidgetState extends State<DeleteCrewMemberWidget> {
  var note = '';

  @override
  Widget build(BuildContext context) {
    bool enabled = note.length >= 10;

    // delete this member
    delete() {
      Navigator.pop(context, 'OK');
    }

    print(enabled);
    return IconButton(
      icon: Icon(Icons.remove_circle),
      onPressed: () => showDialog<String>(
        context: context,
        builder: (BuildContext context) => AlertDialog(
          title: Text('Delete ${widget.position.name}'),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              const Text(
                  'Please enter a reason for not needing this crew member.'),
              TextField(
                maxLines: 4,
                onChanged: (value) => setState(() {
                  note = value;
                  print(note);
                }),
                decoration: InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: 'Enter your reason here',
                ),
              ),
            ],
          ),
          actions: <Widget>[
            TextButton(
              onPressed: () => Navigator.pop(context, 'Cancel'),
              child: const Text('Cancel'),
            ),
            TextButton(
              onPressed: enabled ? () => delete() : null,
              child: const Text('OK'),
            ),
          ],
        ),
      ),
    );
  }
}

When I run it and type in a note, the button stays disabled. I print the value of the state on build, and it does change to enabled as I type. When I get out of the icon and back in, it then shows enabled, even though the note is empty. But it never changes while I’m typing the note.

Any ideas?

3

Answers


  1. I don’t know if I understand correctly, but disable the "OK" button until the user enters a reason:

      onPressed: enabled ? () => note.length >= 10 ? delete() : null : null,
    

    your code:

    class _DeleteCrewMemberWidgetState extends State<DeleteCrewMemberWidget> {
      var note = '';
    
      @override
      Widget build(BuildContext context) {
        bool enabled = note.length >= 10;
    
        // delete this member
        delete() {
          Navigator.pop(context, 'OK');
        }
    
        print(enabled);
        return IconButton(
          icon: Icon(Icons.remove_circle),
          onPressed: () => showDialog<String>(
            context: context,
            builder: (BuildContext context) => AlertDialog(
              title: Text('Delete ${widget.position.name}'),
              content: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  const Text(
                      'Please enter a reason for not needing this crew member.'),
                  TextField(
                    maxLines: 4,
                    onChanged: (value) => setState(() {
                      note = value;
                      print(note);
                    }),
                    decoration: InputDecoration(
                      border: OutlineInputBorder(),
                      hintText: 'Enter your reason here',
                    ),
                  ),
                ],
              ),
              actions: <Widget>[
                TextButton(
                  onPressed: () => Navigator.pop(context, 'Cancel'),
                  child: const Text('Cancel'),
                ),
                TextButton(
                  onPressed: enabled ? () => note.length >= 10 ? delete() : null : null,
                  child: const Text('OK'),
                ),
              ],
            ),
          ),
        );
      }
    }
    

    See if I could help you with the problem.

    Login or Signup to reply.
  2. Ideally you need two things here

    1. An Alert Dialog wrapped in a Stateful Builder to get its state updated.
    2. Reset the value of enabled and note once the dialog is closed. So wait for the Dialog to close and reset the value as per your need.

    Here’s the modified code :

    class _DeleteCrewMemberWidgetState extends State<DeleteCrewMemberWidget> {
      var note = '';
      bool enabled = false;
      @override
      Widget build(BuildContext context) {
        //No longer needed here
        //bool enabled = note.length >= 10;
        delete() {
          Navigator.pop(context, 'OK');
        }
    
        /// print(enabled);
        return IconButton(
            icon: Icon(Icons.remove_circle),
            onPressed: () async {
              String? input = await showDialog<String>(
                context: context,
                builder: (BuildContext context) => StatefulBuilder(
                  builder: (context, setState) {
                    return AlertDialog(
                      title: const Text('Delete Some Name'),
                      content: Column(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          const Text(
                              'Please enter a reason for not needing this crew member.'),
                          TextField(
                            maxLines: 4,
                            onChanged: (value) {
                              if (value.length >= 10) {
                                enabled = true;
                              } else {
                                enabled = false;
                              }
                              print(value);
                              setState(() {});
                            },
                            decoration: const InputDecoration(
                              border: OutlineInputBorder(),
                              hintText: 'Enter your reason here',
                            ),
                          ),
                        ],
                      ),
                      actions: <Widget>[
                        TextButton(
                          onPressed: () => Navigator.pop(context, 'Cancel'),
                          child: const Text('Cancel'),
                        ),
                        TextButton(
                          onPressed: enabled ? () => delete() : null,
                          child: const Text('OK'),
                        ),
                      ],
                    );
                  },
                ),
              );
    
              //You can add a conditional here to check the return String and enable disable likewise
              note = '';
              enabled = false;
    
              setState(() {});
            });
      }
    }
    

    Note: You do not always need to wrap your variables with setState to update. Just calling the setState will automatically update the widget tree with updated variables.

    Login or Signup to reply.
  3. This is a correction with TextEditingController:

    class _DeleteCrewMemberWidgetState extends State<DeleteCrewMemberWidget> {
    
      final noteController = TextEditingController();
      bool noteIsValid = false;
    
      @override
      void dispose() {
        noteController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
    
        // delete this member
        delete() {
          Navigator.pop(context, 'OK');
        }
    
        return IconButton(
          icon: Icon(Icons.remove_circle),
          onPressed: () => showDialog<String>(
            context: context,
            builder: (BuildContext context) => AlertDialog(
              title: Text('Delete ${widget.position.name}'),
              content: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  const Text(
                      'Please enter a reason for not needing this crew member.'),
                  TextField(
                    controller: noteController,
                    maxLines: 4,
                    decoration: InputDecoration(
                      border: OutlineInputBorder(),
                      hintText: 'Enter your reason here',
                    ),
                  ),
                ],
              ),
              actions: <Widget>[
                TextButton(
                  onPressed: () => Navigator.pop(context, 'Cancel'),
                  child: const Text('Cancel'),
                ),
                TextButton(
                  onPressed: noteIsValid ? () => delete() : null,
                  child: const Text('OK'),
                ),
              ],
            ),
          ),
        );
      }
    
      @override
      void initState() {
        super.initState();
        noteController.addListener(() {
          setState(() {
            noteIsValid = noteController.text.length >= 10;
          });
        });
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search