首页 > 解决方案 > Flutter Firestore 集合相关的下拉菜单

问题描述

我正在尝试使用flutter和firestore作为后端来实现级联下拉菜单。到目前为止,这是我的代码,它通过独立加载所有类别和子类别来工作。

class AddProductScreen extends StatefulWidget {
  final ProductData? data;
  AddProductScreen({this.data});
  @override
  AddProductScreenState createState() => AddProductScreenState();
}

class AddProductScreenState extends State<AddProductScreen> {

  AsyncMemoizer categoryMemoizer = AsyncMemoizer<List<CategoryData>>();
  AsyncMemoizer subCategoryMemoizer = AsyncMemoizer<List<SubCategoryData>>();

  CategoryData? selectedCategory;
  SubCategoryData? selectedSubCategory;
  // CategoryData selectedSubCategory;

  List<CategoryData> categories = [];
  List<SubCategoryData> subCategories = [];

  @override
  void initState() {
    super.initState();
    init();
  }

  Future<void> init() async {
    categories = await categoryService.categoriesFuture();
    subCategories = await subCategoryService.categoriesFuture();
    setState(() {});
  }

  @override
  void setState(fn) {
    if (mounted) super.setState(fn);
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      backgroundColor: white,
      appBar: AppBar(
        backgroundColor: white,
        elevation: 0.0,
        title: Text('Title'),
        actions: [
          isUpdate
              ? IconButton(
                  icon: Icon(Icons.delete_forever, color: black),
                  onPressed: () {
                    _showMyDialog();
                  },
                ).paddingOnly(right: 8)
              : SizedBox(),
        ],
      ),
      body: SingleChildScrollView(
        child: Form(
          key: formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              if (categories.isNotEmpty)
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('Select Category', style: boldTextStyle(size: 18)),
                    8.height,
                    Container(
                      width: context.width() * 0.45,
                      decoration: BoxDecoration(
                          borderRadius: radius(), color: Colors.grey.shade200),
                      padding:
                          EdgeInsets.symmetric(horizontal: 16, vertical: 4),
                      child: DropdownButton(
                        underline: Offstage(),
                        items: categories.map((e) {
                          return DropdownMenuItem(
                              child: Text(e.name.validate()), value: e);
                        }).toList(),
                        isExpanded: true,
                        value: selectedCategory,
                        onChanged: (dynamic c) {
                          selectedCategory = c;
                          setState(() {
                          });
                        },
                      ),
                    ),
                  ],
                ),
              if (subCategories.isNotEmpty)
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('Select Sub Category', style: boldTextStyle(size: 18)),
                    8.height,
                    Container(
                      width: context.width() * 0.45,
                      decoration: BoxDecoration(
                          borderRadius: radius(), color: Colors.grey.shade200),
                      padding:
                          EdgeInsets.symmetric(horizontal: 16, vertical: 4),
                      child: DropdownButton(
                        underline: Offstage(),
                        items: subCategories.map((e) {
                          return DropdownMenuItem(
                              child: Text(e.name.validate()), value: e);
                        }).toList(),
                        isExpanded: true,
                        value: selectedSubCategory,
                        onChanged: (dynamic c) {
                          selectedSubCategory = c;
                          setState(() {});
                        },
                      ),
                    ),
                  ],
                ),
            ],
          ).paddingAll(16),
        ),
      ),
    ).cornerRadiusWithClipRRect(16);
  }
}

这是firestore调用

  Future<List<SubCategoryData>> categoriesFuture() async {
    return await ref!.get().then((x) => x.docs
        .map((y) => SubCategoryData.fromJson(y.data() as Map<String, dynamic>))
        .toList());
  }

  Future<List<SubCategoryData>> categoriesFutureById(String? doc) async {
    DocumentReference categoryRef = db.doc('categories/' + doc.toString());
    return await ref!
        .where(SubCategoryKeys.categoryRef, isEqualTo: categoryRef)
        .get()
        .then((x) => x.docs
            .map((y) =>
                SubCategoryData.fromJson(y.data() as Map<String, dynamic>))
            .toList());
  }

调用第一个down的onchanged方法怎么办?

标签: javascriptdrop-down-menuflutter-web

解决方案


我终于通过修改第一个下拉的 onChanged 方法来解决它,如下所示。

onChanged: (dynamic c) {
  selectedCategory = c;
  if (selectedCategory!.id != null) {
    loadSubcategories(selectedCategory!.id);
  }
  setState(() {});
},

Future<void> loadSubcategories(String? docId) async {
    DocumentReference categoryRef = db.doc('categories/' + docId.toString());

    subCategoryService.categoriesFutureById(categoryRef).then((value) {
      // isLoading = false;
      log(value);
      subCategories.clear();
      subCategories.addAll(value);
      selectedSubCategory = subCategories.first;

      setState(() {});
    }).catchError((e) {
      //isLoading = false;
      setState(() {});
      toast(e.toString());
    });
}

推荐阅读