GithubHelp home page GithubHelp logo

Comments (22)

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024

I don't know what exactly is the issue here.
Can you provide a simplified working sample that produce the issue please?

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

Trying to make searchable dropdown but dropdown is list but that list is search from api call
Whenever search it will be call api/network call after that we need to update ui based on api call.
Till i hack and working fine but after that i select item's that item whenever i open it will be selected show but whenever i open search and close and again open that selected value will be delected automatically

image

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

Below simplified version of source code

Main widget which one used for main Page of UI

Container(
              width: 130,
              child: AdvanceDropDownDialog(
                widgetTitle: "Title",
                dropDownValue: listOfValues,  // this listOfValues contain dropdown value
                searchCallBack: (searchKey) {
                  searchRadio(searchKey); // When search happen on actuall in this will call with whatever type in text form field and api call will be happening here after api call success dropdown value need to change and refresh widget
                },
                textEditingController: raTextEditingController,
              ),
            )
class AdvanceDropDownDialog extends StatefulWidget {
  final String widgetTitle;
  final List<dynamic> dropDownValue;
  final Function(String)? searchCallBack;
  final TextEditingController textEditingController;

  const AdvanceDropDownDialog(
      {required this.widgetTitle,
      required this.dropDownValue,
      this.searchCallBack,
      required this.textEditingController,
      Key? key})
      : super(key: key);

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

class _AdvanceDropDownDialogState extends State<AdvanceDropDownDialog> {
  dynamic selectedValue;
  List<dynamic> selectedItems = [];
  bool isExpanded = false;

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

  @override
  void didUpdateWidget(AdvanceDropDownDialog oldWidget) {
    super.didUpdateWidget(oldWidget);
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      builder: (context, snapshoot) {
        return DropdownButtonHideUnderline(
          child: DropdownButton2(
            isExpanded: true,
            dropdownWidth: 300,
            hint: FilterTitleWidget(
                titleText: widget.widgetTitle,
                icon: isExpanded ? Icons.expand_less : Icons.expand_more),
            icon: Container(),
            items: widget.dropDownValue
                .map((item) => DropdownMenuItem<dynamic>(
                      value: item,
                      enabled: false,
                      child: StatefulBuilder(
                        builder: (BuildContext context,
                            void Function(void Function()) change) {
                          final _isSelected = selectedItems.contains(item);
                          return InkWell(
                            onTap: () {
                              _isSelected
                                  ? selectedItems.remove(item)
                                  : selectedItems.add(item);
                              change(() {});
                            },
                            child: Container(
                              height: double.infinity,
                              padding:
                                  const EdgeInsets.symmetric(horizontal: 16.0),
                              color: _isSelected
                                  ? SELECTED_BACKGROUND_COLOR
                                  : null,
                              child: Row(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceBetween,
                                crossAxisAlignment: CrossAxisAlignment.center,
                                children: [
                                  Text(
                                    (item is CustomObj)
                                        ? item.name
                                        : item['name'],
                                  ),
                                  _isSelected
                                      ? Icon(Icons.check)
                                      : const SizedBox(),
                                ],
                              ),
                            ),
                          );
                        },
                      ),
                    ))
                .toList(),
            value: selectedValue,
            onChanged: (dynamic value) {},
            buttonHeight: 40,
            itemHeight: 40,
            alignment: Alignment.center,
            dropdownMaxHeight: 200,
            searchController: widget.textEditingController,
            searchInnerWidget: Padding(
              padding: const EdgeInsets.only(
                top: 8,
                // bottom: 4,
                right: 0,
                left: 0,
              ),
              child: TextFormField(
                controller: widget.textEditingController,
                onChanged: (value) {
                  if (widget.searchCallBack != null) {
                    widget.searchCallBack!(value);
                  }
                },
                decoration: InputDecoration(
                  isDense: true,
                  contentPadding: EdgeInsets.only(left: 32, top: 16),
                  suffixIcon: Icon(Icons.search_rounded),
                  hintText: "Search ...",
                ),
              ),
            ),
            searchMatchFn: (item, searchValue) {
              return (item.value
                  .toString()
                  .toLowerCase()
                  .contains(searchValue.toLowerCase()));
            },
            onMenuStateChange: (isOpen) {
              if (!isOpen) {}
              isExpanded = isOpen;
            },
          ),
        );
      },
    );
  }
}

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024

Is your issue that the dropdown menu items don't update when you call api?

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

Yes after api call that not update & selected item i have customized changing background color and right tick mark that also automatically deselect

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024

Currently updating an open Dropdown Menu is not fully supported but there's a hacky solution for this as described here #101

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

Actually this one tried but not working

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024

Are you currently able to update the menu when its open?

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

yes

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

Main problem is selected items not refresh

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024
onTap: () {
    _isSelected
        ? selectedItems.remove(item)
        : selectedItems.add(item);
    change(() {});
    //Add this.. This rebuilds the main StatefulWidget
    setState(() {});
  },

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

yes actually did this but when two to three time open close dropdown it will be automatically deselect

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

** Please keep in mind i am using like reusable widget like multiple instance

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024

yes actually did this but when two to three time open close dropdown it will be automatically deselect

I'm not sure why this is happening so I need to test your code.
Can you update your code so I can actually run it? Currently your sample has different dependencies which I don't have.

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

latest one shared that have no different dependencies
If possible we can connect also

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024

Actually it has dependencies.
I can't run it on a new flutter project.

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024

Open new flutter project and try to let your sample code work on it so I can test it too.
For the api call, you can simulate it by await Future.delayed

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

Okay sending you with open create new flutter project and adding all on that

from dropdown_button2.

radheyshyamjat avatar radheyshyamjat commented on June 16, 2024

Full example added please check

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

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

class _AdvanceDialogState extends State<AdvanceDialog> {
  final TextEditingController searchController = TextEditingController();
  final TextEditingController searchController2 = TextEditingController();
  List<dynamic> dropdownValue = [
    "Aetna",
    "Allegiance",
    "Anthem",
    "BlueCross",
    "BlueCrossandBlueShield",
    "BlueShield",
    "Children'sProgram",
    "CHIP",
    "Cigna",
    "FirstChoiceHealth",
    "Humana",
    "Kaiser(Out-of-Network)",
    "Magellan",
    "Medicaid",
    "Medicare",
    "MHNetBehavioralHealth",
    "Optum",
    "OtherInsuranceEBMS",
    "OutofNetwork",
    "PacificSource",
    "TRICARE",
    "TriWest",
    "UMR",
    "UnitedHealthcare"
  ];

  List<dynamic> searchItems = [];
  List<dynamic> searchItems2 = [];
  List<dynamic> dropdownValue2 = [
    "Aetna",
    "Allegiance",
    "Anthem",
    "BlueCross",
    "BlueCrossandBlueShield",
    "BlueShield",
    "Children'sProgram",
    "CHIP",
    "Cigna",
    "FirstChoiceHealth",
    "Humana",
    "Kaiser(Out-of-Network)",
    "Magellan",
    "Medicaid",
    "Medicare",
    "MHNetBehavioralHealth",
    "Optum",
    "OtherInsuranceEBMS",
    "OutofNetwork",
    "PacificSource",
    "TRICARE",
    "TriWest",
    "UMR",
    "UnitedHealthcare"
  ];

  @override
  void initState() {
    super.initState();
    searchItems = dropdownValue;
    searchItems2 = dropdownValue2;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          AdvanceDropDownDialog(
              dropDownValue: searchItems,
              textEditingController: searchController,
              searchCallBack: (p0) {
                getValue(p0);
              }),
          AdvanceDropDownDialog(
              dropDownValue: searchItems2,
              textEditingController: searchController2,
              searchCallBack: (p0) {
                getValue2(p0);
              })
        ],
      ),
    );
  }

  getValue(String searchKey) async {
    print("Search key $searchKey");
    if (searchKey.isNotEmpty) {
      await Future.delayed(const Duration(seconds: 1));
      searchItems.clear();
      dropdownValue.forEach((element) {
        if (element.toString().contains(searchKey)) {
          searchItems.add(element);
        }
      });
    } else {
      searchItems = dropdownValue;
    }
    setState(() {});
  }

  getValue2(String searchKey) async {
    print("Search key $searchKey");
    if (searchKey.isNotEmpty) {
      searchItems2.clear();
      dropdownValue2.forEach((element) {
        if (element.toString().contains(searchKey)) {
          searchItems2.add(element);
        }
      });
    } else {
      searchItems2 = dropdownValue2;
    }
    setState(() {});
  }

  @override
  void dispose() {
    searchController.dispose();
    searchController2.dispose();
    super.dispose();
  }
}

class AdvanceDropDownDialog extends StatefulWidget {
  final List<dynamic> dropDownValue;
  final Function(String)? searchCallBack;
  final TextEditingController textEditingController;

  const AdvanceDropDownDialog(
      {required this.dropDownValue,
      this.searchCallBack,
      required this.textEditingController,
      Key? key})
      : super(key: key);

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

class _AdvanceDropDownDialogState extends State<AdvanceDropDownDialog> {
  dynamic selectedValue;
  List<dynamic> selectedItems = [];
  bool isExpanded = false;

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

  @override
  void didUpdateWidget(AdvanceDropDownDialog oldWidget) {
    super.didUpdateWidget(oldWidget);
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      builder: (context, snapshoot) {
        return DropdownButtonHideUnderline(
          child: DropdownButton2(
            isExpanded: true,
            dropdownWidth: 300,
            hint: Container(
              height: 17,
              margin: const EdgeInsets.symmetric(horizontal: 5),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: const [
                  Text("Title Text"),
                  SizedBox(width: 5),
                  Icon(Icons.expand_less),
                ],
              ),
            ),
            icon: Container(),
            items: widget.dropDownValue
                .map((item) => DropdownMenuItem<dynamic>(
                      value: item,
                      enabled: false,
                      child: StatefulBuilder(
                        builder: (BuildContext context,
                            void Function(void Function()) change) {
                          final _isSelected = selectedItems.contains(item);
                          return InkWell(
                            onTap: () {
                              _isSelected
                                  ? selectedItems.remove(item)
                                  : selectedItems.add(item);
                              change(() {});
                            },
                            child: Container(
                              height: double.infinity,
                              padding:
                                  const EdgeInsets.symmetric(horizontal: 16.0),
                              color: _isSelected
                                  ? Colors.tealAccent.shade400
                                  : null,
                              child: Row(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceBetween,
                                crossAxisAlignment: CrossAxisAlignment.center,
                                children: [
                                  Text(item),
                                  _isSelected
                                      ? const Icon(Icons.check)
                                      : const SizedBox(),
                                ],
                              ),
                            ),
                          );
                        },
                      ),
                    ))
                .toList(),
            value: selectedValue,
            onChanged: (dynamic value) {},
            buttonHeight: 40,
            itemHeight: 40,
            alignment: Alignment.center,
            dropdownMaxHeight: 200,
            searchController: widget.textEditingController,
            searchInnerWidget: Padding(
              padding: const EdgeInsets.only(
                top: 8,
                // bottom: 4,
                right: 0,
                left: 0,
              ),
              child: TextFormField(
                controller: widget.textEditingController,
                onChanged: (value) {
                  if (widget.searchCallBack != null) {
                    widget.searchCallBack!(value);
                  }
                },
                decoration: const InputDecoration(
                  isDense: true,
                  contentPadding: EdgeInsets.only(left: 32, top: 16),
                  suffixIcon: Icon(Icons.search_rounded),
                  hintText: "Search ...",
                ),
              ),
            ),
            onMenuStateChange: (isOpen) {
              if (!isOpen) {}
              isExpanded = isOpen;
            },
          ),
        );
      },
    );
  }
}

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024

This can be tested, Thanks!
What are the steps to produce the issue?

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024

Here you're doing searchItems.clear() and as searchItems is the same reference as dropdownValue, the forEach will never execute.

await Future.delayed(const Duration(seconds: 1));
      searchItems.clear();
      //This forEach never execute
      dropdownValue.forEach((element) {
        if (element.toString().toLowerCase().contains(searchKey)) {
          searchItems.add(element);
        }
      });

You need to clone the list in initState instead of copying the object reference:

  @override
  void initState() {
    super.initState();
    searchItems = [...dropdownValue];
  }

Another thing is as you're using the default SearchMatchFn you need to add toLowerCase() to your condition:

  dropdownValue.forEach((element) {
    if (element.toString().toLowerCase().contains(searchKey.toLowerCase())) {
      searchItems.add(element);
    }
  });

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 16, 2024

As this is unrelated to the package, I'll close it.
Feel free to ask for re-open if you disagree.

from dropdown_button2.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.