简体   繁体   中英

filter a list with multiple dropdowns in dart

hey there thanks for checking out my question, i am making a app that connects to an api and pulls back the json data like so

主屏幕 i have been trying to get a filter system to work so for example the list can be sorted by a certain series and other options, i have two lists in the code one for all of the results from the api called _userdetails and one for the search result called _searchresult.

my goal is to have the filters and search bar working in sync, so for example you could filter for a series called one piece and then filter that new list with the other filters to narrow down the results and even use the search bar on these new lists.

at the moment i have the filters working to a extent if the series is selected as dragonball it will select all of the dragon ball characters but once a new filter or the search is used it just resets the list here is the code for the dropdown

new Row(
          mainAxisAlignment: MainAxisAlignment.start,
          mainAxisSize: MainAxisSize.max,
          crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                 // Text("Select a series"),


                new  DropdownButton<String>(
                    hint: Text("Series"),
                   // value: null,

                    items: _fieldList.map((value){
                      return DropdownMenuItem<String>(
                        value: value.series,
                        child: Container(
                          width: 100,
                        child: new Text(value.series),
                       // height: 5.0,
                          ),
                      );
                    }).toList(),
                    onChanged: (String val) {
                      _selectedText = val;
                      setState(() {
                       // _searchResult.clear();
                      //  _searchResult.removeWhere((userDetail) => userDetail.series != _selectedText);
                         // _newList.clear();
                        _selectedText = val;
                        _userDetails.forEach((userDetail) {

                          if(userDetail.series.contains(_selectedText)){
                            userDetail.remove((userDetail) => userDetail.series != _selectedText);
                            _searchResult.add(userDetail);}
                          if(_searchResult.contains(_selectedText))
                            _searchResult.removeWhere((userDetail) => userDetail.series != _selectedText);

                          //   _userDetails.where((f) => f.series.contains(_selectedText)).toList(); //apples

                          print(_searchResult.length);

                        });
                        print(_selectedText);
                      });
                    },
                  ),

                 new DropdownButton<String>(
                    hint: Text("Class"),
                    // value: null,

                    items: _fieldList.map((value){
                      return DropdownMenuItem<String>(
                        value: value.classs,
                        child: new Text(value.classs),
                      );
                    }).toList(),
                    onChanged: (String val) {
                      _selectedText = val;
                      setState(() {

                        _searchResult.removeWhere((userDetail) => userDetail.classs != _selectedText);

                        _userDetails.forEach((userDetail) {
                        if (userDetail.classs.contains(_selectedText))
                          ///loops thrpugh each user detail and add where selectedtext = whatever
                        //  _searchResult.removeWhere((_searchResult) => userDetail.classs != _selectedText);
                          _searchResult.removeWhere((userDetail) => userDetail.classs != _selectedText);

                        _searchResult.add(userDetail);
                      //  _userDetails.where((f) => f.classs.contains(_selectedText)).toList(); //apples

                       /// _searchResult.add(userDetail);

                        });

                           // _searchResult.add(userDetail);
                          print(_selectedText);
                          //_searchResult.remove(userDetail.classs.)

                          //_newList.add(userDetail);
                          print(_searchResult.length);

                       // });
                        print(_selectedText);
                      });
                    },
                  ),
                  SizedBox(
                    height: 5.0,
                  ),
                  Text('Selected: ${_selectedText}'),
                ],
              ),

here is the code for the listview

new Expanded(
            child: _searchResult.length != 0 || controller.text.isNotEmpty
                ? new ListView.builder(
              itemCount: _searchResult.length,
              itemBuilder: (context, i) {
                return new Card(
                  child: new ListTile(
                    leading: new CircleAvatar(backgroundImage: new NetworkImage("https://ochd.co.uk/db/puti/Assets/Portraits/"+_searchResult[i].portrait,),),
                    title: new Text(_searchResult[i].name),
                    subtitle: new Text(_searchResult[i].classs),
                    onTap: () {
                      Navigator.push(context, new MaterialPageRoute(builder: (context) => DetailPage(_searchResult[i])));},
                  ),
                  margin:
                  const EdgeInsets.all(0.0),
                );
              },
            )
                : new ListView.builder(
              itemCount: _userDetails.length,
              itemBuilder: (context, index) {
                return new Card(
                  child: new ListTile(
                    leading: new CircleAvatar(backgroundImage: new NetworkImage("https://ochd.co.uk/db/puti/Assets/Portraits/"+_userDetails[index].portrait,),),
                    title: new Text(_userDetails[index].name),
                    subtitle: new Text(_userDetails[index].classs),
                    trailing: new CircleAvatar(backgroundImage: new NetworkImage("https://ochd.co.uk/db/puti/Assets/"+_userDetails[index].type,),),
                    onTap: () {
                      Navigator.push(context, new MaterialPageRoute(builder: (context) => DetailPage(_userDetails[index])));},
                  ),
                  margin: const EdgeInsets.all(0.0),
                );
              },
            ),

          ),

im a little bit stumped lol

The reason you keep resetting the list after you search or change filters is you are calling setstate and assigning the value _selectedText = val. You are assigning a new value to the selectedText.

//Excerpt from your code

onChanged: (String val) {
      setState(() {
     /// When the dropdown value changes you are assigning a new value to selected 
     /// text
     /// Assuming it had Goto and the user selected Vegeta, the new value of 
     /// selectedText will be Vegeta
     _selectedText = val;
     // The statement that follows will evaluate based on the new value 
   });
  });

I would suggest either using an objected oriented approach and creating models from those fields and use the i,e series and class OR using a map instead of a string. If you find it more comfortable with strings have strings equivalent to the number of filtersi.e convert the selectedText to Map. Since you are using the DropdownMenu my assumption is you only want one value from each filter

///Initialize your set outside the build method and results
final Map<String,String> selected = {"series":"","class":""}

/// Initialized the results list with the initial result set 
List results = userDetails;

/// Method to build your results

void buildResults(){
  setState((){
    var seriesList = 

/// comparing strings in dart is case sensitive so 
///  depending on your data you may consider 
/// converting all the strings you are comparing to lowercase 
 _userList
 .where((userDetail)=>userDetail
 .series
 .toLowerCase()
  .contains(selected["series"]))).toList();

  var classList = 
  _userList
  .where((userDetail)=>userDetail
  .class.toLowerCase()
  .contains(selected["class"]))).toList();
 
  /// Merge the two lists using spread operator
  /// Assuming you are using Dart > 2.3
  var list3 = [...seriesList, ...classList];

  results = list3;
 
});
}

/// onChanged method of Dropdown button
/// Assuming this is the series dropdown
setState((){
  selected.update(
   "series", 
    // if it is already in the map
   (existingValue) => value, 
   ifAbsent: () => value,
 );
buildResults();
});






 /// In your listview builder
 ListView.builder(
 itemCount: results.length, 
 itemBuilder:(context,index){
}

You can find a more efficient way. You dont need to call setstate twice I have done.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM