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.