skip to Main Content

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

2

Answers


  1. when setting up the value for the _usersDeptName, you are converting it to string, this is not right because now the items and the selected items is 2 different thing,

    so if you want it to be the department name, then when setting up the value for _usersDeptName, make it bind to the department name:
    example

     setState(() {
        _usersDeptName = newValue.departmentName;
        print('$_usersDeptName is selected');
    });
    
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search