flutterdartdropdownbuttonflutter-showmodalbottomsheet

Flutter dropdownbutton changed value is not displaying


I'm new in flutter. I've created a simple project. It is fetching documents of person collection from cloud firestore. There is a modal screen to create new person document (it is opening When I touch the + button)

I have a problem In that modalBottomSheet I can see the new value of department dropDownButton on the log screen but user interface are not changing.

I think it is related to 'context' but I couldn't solve the problem

Here is my code:

import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

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

  @override
  _PersonState createState() => _PersonState();
}

class _PersonState extends State<Person> {
  final TextEditingController _nameController = TextEditingController();
  final CollectionReference _person = FirebaseFirestore.instance.collection('person');
  final CollectionReference _department = FirebaseFirestore.instance.collection('department');
  String? _usersDeptName;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
          child: Column(
            children: [
              Expanded(
                child: StreamBuilder(
                  stream: _person.snapshots(),
                  builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
                    if (streamSnapshot.hasData) {
                      return ListView.builder(
                        itemCount: streamSnapshot.data!.docs.length,
                        itemBuilder: (context, index) {
                          final DocumentSnapshot documentSnapshot = streamSnapshot.data!.docs[index];
                          return Card(
                            margin: const EdgeInsets.all(10),
                            child: ListTile(
                              title: Text(documentSnapshot['personName']),
                              subtitle: Text(documentSnapshot['departmentName'] ?? '?'),
                            ),
                          );
                        },
                      );
                    }
                    return const Center(
                      child: CircularProgressIndicator(),
                    );
                  },
                ),
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => {_create()},
          child: const Icon(Icons.add),
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat);
  }

  Future<void> _create() async {
    _usersDeptName = null;
    await showModalBottomSheet(
      isScrollControlled: true,
      context: context,
      builder: (BuildContext ctx) {
        return Padding(
          padding: EdgeInsets.only(top: 20, left: 20, right: 20, bottom: MediaQuery.of(context).viewInsets.bottom + 20),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              TextField(controller: _nameController, decoration: InputDecoration(labelText: 'person_name'.tr())),
              const SizedBox(height: 10),
              StreamBuilder<QuerySnapshot>(
                stream: _department.snapshots(),
                builder: (context, snapshot) {
                  if (!snapshot.hasData) {
                    return Text("loading").tr();
                  } else {
                    List<DropdownMenuItem> departments = [];
                    int? howManyRecords = snapshot.data?.size;
                    for (int i = 0; i < howManyRecords!; i++) {
                      DocumentSnapshot snap = snapshot.data?.docs[i] as DocumentSnapshot<Object?>;
                      departments.add(DropdownMenuItem(child: Text(snap.get('departmentName')), value: snap.get('departmentName')));
                    }
                    return Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Expanded(
                          child: DropdownButton(
                            value: _usersDeptName,
                            items: departments,
                            onChanged: (newValue) {
                              setState(() {
                                _usersDeptName = newValue.toString();
                                print('$_usersDeptName is selected');
                              });
                            },
                            isExpanded: true,
                          ),
                        ),
                      ],
                    );
                  }
                },
              ),
              ElevatedButton(
                child: const Text('save').tr(),
                onPressed: () async {
                  final String name = _nameController.text;
                  if (name != null) {
                    await _person.add({"personName": name, 'departmentName': _usersDeptName});
                    _nameController.text = '';
                    Navigator.of(context).pop();
                  }
                },
              )
            ],
          ),
        );
      },
    );
  }
}

person list modalBottomSheet dropDownList


Solution

  • Try using StatefulBuilder to update the bottomSheet state.

      Future<void> _create() async {
        _usersDeptName = null;
        await showModalBottomSheet(
          isScrollControlled: true,
          context: context,
          builder: (BuildContext ctx) {
            return StatefulBuilder(
              builder: (context, setState) => Padding(
                padding: EdgeInsets.only(
    

    If you like to change the widget-state(main UI) at the same time, you can rename the StatefulBuilder's setState and call both on onChanged.