简体   繁体   English

在 dart 中过滤具有多个下拉列表的列表

[英]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嘿,感谢您检查我的问题,我正在制作一个连接到 api 并像这样拉回 json 数据的应用程序

主屏幕 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.我一直在尝试让过滤系统正常工作,例如列表可以按某个系列和其他选项排序,我在代码中有两个列表,一个是来自名为 _userdetails 的 api 的所有结果,另一个是用于搜索结果称为_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.我的目标是让过滤器和搜索栏同步工作,例如,您可以过滤一个名为 onepiece 的系列,然后使用其他过滤器过滤该新列表以缩小结果范围,甚至在这些新列表上使用搜索栏列表。

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.您在搜索或更改过滤器后不断重置列表的原因是您正在调用 setstate 并分配值 _selectedText = val。 You are assigning a new value to the selectedText.您正在为 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.我建议使用面向对象的方法并从这些字段创建模型,并使用 i、e 系列和类或使用映射而不是字符串。 If you find it more comfortable with strings have strings equivalent to the number of filtersi.e convert the selectedText to Map.如果您觉得字符串更适合具有与过滤器数量相等的字符串,即将 selectedText 转换为 Map。 Since you are using the DropdownMenu my assumption is you only want one value from each filter由于您使用的是 DropdownMenu,我的假设是您只需要每个过滤器中的一个值

///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.你不需要我两次调用 setstate 。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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