flutterfirebasetextfieldflutter-alertdialog

Flutter textFiled input is always save the change in AlertDialog widget


I have problem that create cancel button in textField.

But it's always save changing cancel button and submit button both

If I delete the cancel button code, it's also save the change of textField when pop alertdialog by clicking background

I find some video and document but there is not different in code

https://www.youtube.com/watch?v=TpW7nLL57uQ

Below: My AlertDialog code

Future<void> editField(String field) async {
    String newValue = '';
    await showDialog(
      context: context,
      builder: (context) => AlertDialog(
        backgroundColor: Colors.grey[100],
        title: Text(
          "Edit $field",
          style: const TextStyle(color: Colors.black),
        ),
        content: TextField(
          autofocus: true,
          style: const TextStyle(color: Colors.black),
          decoration: InputDecoration(
            hintText: "Enter new $field",
            hintStyle: const TextStyle(color: Colors.grey),
          ),
          onChanged: (value) {
            newValue = value;
          },
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(newValue),
            child: const Text('Submit'),
          ),
        ],
      ),
    );
    if (newValue.trim().isNotEmpty) {
      await userCollection.doc(currentUser.email).update({field: newValue});
    }
  }

Solution

  • Your code make newValue is a global value, it will change on this callback

    onChanged: (value) {
       newValue = value;
    },
    

    no matter what you pop from Dialog. So you should use a local value dialogValue in Dialog and pop it when you press Submit button

    showDialog is a Future function that return result after you

    Navigator.pop(context, result) in Dialog. Example:

    final result = await showDialog(...);
    

    or

    var result;
    showDialog(...).then((value) {
       result = value;
    });
    

    two ways above is the same.

    Try this code:

      Future<void> editField(String field) async {
        String newValue = '';
        
        await showDialog(
          context: context,
          builder: (context) {
            String dialogValue = '';
            return AlertDialog(
              backgroundColor: Colors.grey[100],
              title: Text(
                "Edit $field",
                style: const TextStyle(color: Colors.black),
              ),
              content: TextField(
                autofocus: true,
                style: const TextStyle(color: Colors.black),
                decoration: InputDecoration(
                  hintText: "Enter new $field",
                  hintStyle: const TextStyle(color: Colors.grey),
                ),
                onChanged: (value) {
                  dialogValue = value;
                },
              ),
              actions: [
                TextButton(
                  onPressed: () => Navigator.pop(context),
                  child: const Text('Cancel'),
                ),
                TextButton(
                  onPressed: () => Navigator.of(context).pop(dialogValue),
                  child: const Text('Submit'),
                ),
              ],
            );
          },
        ).then((value) {
          newValue = value;
        });
        
        if (newValue.trim().isNotEmpty) {
          await userCollection.doc(currentUser.email).update({field: newValue});
        }
      }