2

I have seen other responses to questions similar to this, but none of those solutions have worked for me. I am trying to update a text field with a date that has been selected after closing a showDatePicker window, but the Text does not update? I'm not certain why the setState() call does not update the Text. Printing to the console shows that the variable is updated, but the Text does not change. I initially used a String variable to hold the Text information and then changed it to a TextEditingController but that did not help either. Is the display immutable, and if so, is there a way to update the Text after the date has been selected?

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
  return MaterialApp(
    title: 'Date Test',
    theme: ThemeData(
      primarySwatch: Colors.blue,
    ),
    home: const PickDate(),
   );
 }
}

class PickDate extends StatefulWidget {
  const PickDate({Key? key}) : super(key: key);

  @override
  State<PickDate> createState() => _PickDateState();
}

class _PickDateState extends State<PickDate> {
  DateTime selectedDate = DateTime.now();
  final DateFormat formatter = DateFormat('MM/dd/yy');
  var dateController = TextEditingController();

  @override
  void initState() {
    super.initState();
    dateController.text = formatter.format(selectedDate);
  }

  Future<void> _selectDate(BuildContext context) async {
    final DateTime? picked = await showDatePicker(
        context: context,
        initialDate: selectedDate,
        firstDate: DateTime(2022, 5),
        lastDate: DateTime(2023));
    if (picked != null && picked != selectedDate) {
      setState(() {
        selectedDate = picked;
        dateController.text = formatter.format(selectedDate);
        print('Select Date: ${dateController.text}');
      });
    }
  }

  Future<String?> displayDialog(BuildContext context, String title) async {
    Widget dialogWithTextField(BuildContext context) => Container(
          height: 300,
          decoration: const BoxDecoration(
            color: Colors.white,
            shape: BoxShape.rectangle,
            borderRadius: BorderRadius.all(Radius.circular(12)),
          ),
          child: Column(
            children: <Widget>[
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  Text(dateController.text),
                  ElevatedButton.icon(
                      onPressed: () async {
                        await _selectDate(context);
                        setState(() {
                          dateController.text = formatter.format(selectedDate);
                          print(dateController.text);
                        });
                      },
                      icon: const Icon(Icons.date_range_sharp),
                      label: const Text('Pick Date')),
                ],
              ),
              Row(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).pop('x');
                    },
                    child: const Text(
                      "Cancel",
                    ),
                  ),
                  ElevatedButton(
                    style: ButtonStyle(
                      backgroundColor:
                          MaterialStateProperty.all(Colors.lightBlue),
                    ),
                    child: Text(
                      "Save".toUpperCase(),
                    ),
                    onPressed: () {
                      Navigator.of(context).pop('');
                    },
                  )
                ],
              ),
            ],
          ),
        );

    return showDialog(
        context: context,
        builder: (BuildContext context) {
          return Dialog(
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(50),
            ),
            elevation: 6,
            backgroundColor: Colors.transparent,
            child: dialogWithTextField(context),
           );
        });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Test'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
                 onPressed: () {
                   displayDialog(context, 'New Date');
                },
                child: const Text('New Date')),
           ],
        ),
      ),
    );
  }
}

1 Answer 1

4

The widget displayed by showDialog is not the widget you are using to call showDialog, therefore calling setState in your widget will not cause the already mounted widget to be rebuilt. In order to make this work you can extract your dialog into a separate StatefulWidget. Here's a full example based on your code:

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Date Test',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const PickDate(),
    );
  }
}

class MyDialog extends StatefulWidget {
  final TextEditingController dateController;
  const MyDialog({required this.dateController, Key? key}) : super(key: key);

  @override
  State<MyDialog> createState() => _MyDialogState();
}

class _MyDialogState extends State<MyDialog> {
  DateTime selectedDate = DateTime.now();
  final DateFormat formatter = DateFormat('MM/dd/yy');

  Future<void> _selectDate(BuildContext context) async {
    final DateTime? picked = await showDatePicker(
        context: context, initialDate: selectedDate, firstDate: DateTime(2022, 5), lastDate: DateTime(2023));
    if (picked != null && picked != selectedDate) {
      setState(() {
        selectedDate = picked;
        widget.dateController.text = formatter.format(selectedDate);
        print('Select Date: ${widget.dateController.text}');
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 300,
      decoration: const BoxDecoration(
        color: Colors.white,
        shape: BoxShape.rectangle,
        borderRadius: BorderRadius.all(Radius.circular(12)),
      ),
      child: Column(
        children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              Text(widget.dateController.text),
              ElevatedButton.icon(
                  onPressed: () async {
                    await _selectDate(context);
                    setState(() {
                      widget.dateController.text = formatter.format(selectedDate);
                      print(widget.dateController.text);
                    });
                  },
                  icon: const Icon(Icons.date_range_sharp),
                  label: const Text('Pick Date')),
            ],
          ),
          Row(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop('x');
                },
                child: const Text(
                  "Cancel",
                ),
              ),
              ElevatedButton(
                style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.all(Colors.lightBlue),
                ),
                child: Text(
                  "Save".toUpperCase(),
                ),
                onPressed: () {
                  Navigator.of(context).pop('');
                },
              )
            ],
          ),
        ],
      ),
    );
  }
}

class PickDate extends StatefulWidget {
  const PickDate({Key? key}) : super(key: key);

  @override
  State<PickDate> createState() => _PickDateState();
}

class _PickDateState extends State<PickDate> {
  var dateController = TextEditingController();

  DateTime selectedDate = DateTime.now();
  final DateFormat formatter = DateFormat('MM/dd/yy');

  @override
  void initState() {
    super.initState();
    dateController.text = formatter.format(selectedDate);
  }

  Future<String?> displayDialog(BuildContext context, String title) async {
    return showDialog(
        context: context,
        builder: (BuildContext context) {
          return Dialog(
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(50),
            ),
            elevation: 6,
            backgroundColor: Colors.transparent,
            child: MyDialog(
              dateController: dateController,
            ),
          );
        });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Test'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
                onPressed: () {
                  displayDialog(context, 'New Date');
                },
                child: const Text('New Date')),
          ],
        ),
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the quick and accurate response!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.