Reputation: 597
so i was creating this app which is an item catalogue for an online shop using StaggeredGridView, here i add a function to sort the item from a list, so that i can sort it by price or make it back to default sorting, but i encounter a problem where the list cant go back to default sorting when i select it, here is the code :
class ItemCatalogState extends State<ItemCatalog>{
sortedBy sorted = sortedBy.init;
bool isInit = true;
var selectedList = [];
void sortItem(List<Item> initialList){
switch (sorted) {
case sortedBy.lowestPrice:
setState(() {
selectedList.sort((a,b){return a.price.compareTo(b.price);});
});
break;
case sortedBy.highestPrice:
setState(() {
selectedList.sort((a,b){return b.price.compareTo(a.price);});
});
break;
case sortedBy.init:
//NOT WORKING
setState(() {
selectedList = initialList;
});
break;
default:
}
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
List<Item> itemList = Provider.of<List<Item>>(context);
if(isInit&&itemList!=null){
selectedList = itemList.map((e) => Item(image: e.image,name: e.name,isReady: e.isReady,price: e.price,seller: e.seller)).toList();
isInit = false;
}
sortItem(itemList);
return Container(
child: DropdownButtonHideUnderline(
child: DropdownButton(
value: sorted,
items: [
DropdownMenuItem(
child: Text('Default',),
value: sortedBy.init,),
DropdownMenuItem(
child: Text('Lowest',),
value: sortedBy.lowestPrice,),
DropdownMenuItem(
child: Text('Highest'),
value: sortedBy.highestPrice,),
],
onChanged: (value){
setState(() {
sorted = value;
});
}),
),
),
Container(
decoration: BoxDecoration(
color: kGrayMainColor,
),
child: StaggeredGridView.countBuilder(
itemCount: selectedList!=null?selectedList.length:itemList.length,
crossAxisCount: 2,
itemBuilder: (context, index) {
Item currentItem = selectedList!=null?selectedList[index]:itemList[index];
return ItemTile(item: currentItem, size: size,);
},
),
),
),
]),]
);
}
It was supposed to call the original List when i click the default drop down, but nothing changed, could i possibly wrong at copying the list to selectedList? Thankyou and any advice regarding my other bad code practice is appreciated since im still learning.
Upvotes: 0
Views: 618
Reputation: 24736
Inside sortItems
you set selectedList
to be equal to initialList
. From that point on, both variables are now pointing at the same collection of objects, which means anything you do to one, you will also do to the other. And since you are getting the collection through provider, these changes will also affect the original list that was provided.
Instead of a direct assignment, copy initialList
again so that the two lists are never pointing to the same collection.
Incidentally, there's a much easier way to create copies of lists:
selectedList = List.from(initialList);
On another note, I'm assuming that the default value of sorted
is sortedBy.init
. That makes the initial copy within your build
method redundant as the sortItems
method immediately overwrites the value of selectedList
. Instead, just depend on sortItems
to generate your list without having to worry about initialization:
void sortItem(List<Item> initialList){
switch (sorted) {
case sortedBy.lowestPrice:
selectedList = List.from(initialList)
..sort((a,b) => a.price.compareTo(b.price));
break;
case sortedBy.highestPrice:
selectedList = List.from(initialList)
..sort((a,b) => b.price.compareTo(a.price));
break;
case sortedBy.init:
selectedList = List.from(initialList);
break;
}
setState(() {}); // Just call this once to reduce code duplication and verbosity
}
@override
Widget build(BuildContext context) {
...
List<Item> itemList = Provider.of<List<Item>>(context);
sortItems(itemList);
...
}
Upvotes: 1
Reputation: 1373
This is how I would solve it (I changed your List<Item>
to a List<String>
for simplicity, but you get the gist):
Load the original list into the _sortedList variable (initially in didChangeDependencies) via the Provider and repeat this whenever you are in need of the original list again.
(My Provider returns ['aa', 'dd', 'cc']
, so I could get in that map() you do on the list as well :) )
enum SortOrder { ascending, descending, original }
class _TestState extends State<Test> {
var _sortedList = List<String>();
@override
void didChangeDependencies() {
super.didChangeDependencies();
_loadOriginalList();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
RaisedButton(
child: Text('Ascending'),
onPressed: () => setState(() => _sortList(SortOrder.ascending)),
),
RaisedButton(
child: Text('Descending'),
onPressed: () => setState(() => _sortList(SortOrder.descending)),
),
RaisedButton(
child: Text('Original'),
onPressed: () => setState(() => _sortList(SortOrder.original)),
),
],
),
ListView.builder(
shrinkWrap: true,
itemCount: _sortedList.length,
itemBuilder: (context, index) => Center(
child: Text(_sortedList[index]),
),
),
],
),
);
}
void _sortList(SortOrder sortOrder) {
switch (sortOrder) {
case SortOrder.ascending:
_sortedList.sort();
break;
case SortOrder.descending:
_sortedList.sort();
_sortedList = _sortedList.reversed.toList();
break;
case SortOrder.original:
_loadOriginalList();
break;
}
}
void _loadOriginalList() {
final originalList = Provider.of<List<String>>(context, listen: false);
_sortedList.clear();
_sortedList.addAll(originalList.map((e) => e.substring(0, 1)));
}
}
Upvotes: 0