Reputation: 678
When I tried to remove an item, every time the last item get removed. After searching for solutions, I found out it works this way with stateful widgets, and the solution is to add keys in the widgets.
So I added keys but the problem isn't gone. The last item still gets removed. Bellow, I tried to show the situation as detailed as possible. At the very last, you will see, when I remove the item at index(0) it gets called but index(1) gets disposed from the UI. But in the list, the 1st item got removed properly.
This is the ListView.builder
ListView.builder(
primary: false,
shrinkWrap: true,
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
itemCount: saleItems.length,
itemBuilder: (BuildContext context, int index) {
print('Value key: ${ValueKey(index)}');
return ProductItemWidget(
key: ValueKey(index),
itemContext: context,
mainItems: batches,
onDelete: () {
setState(() {
saleItems.remove(saleItems[index]);
print(
'deleted $index - value ${ValueKey(index)}');
print(saleItems);
});
},
onNewSaleItem: (newItem) {
setState(() {
saleItems[index] = newItem;
});
print(saleItems);
},
);
},
),
Adding new items to the list
SizedBox(
key: _addButtonKey,
child: KFilledButton(
text: 'New Sale Item',
onPressed: () {
setState(() {
saleItems.add(newSaleItemModal);
});
scrollToAddButton();
},
),
),
Instance of the item and the list
NewSaleItemModal newSaleItemModal = NewSaleItemModal();
List<NewSaleItemModal> saleItems = [];
ProductItemWidget() page
This is the Constructor
class ProductItemWidget extends StatefulWidget {
void Function() onDelete;
List<dynamic>? mainItems;
BuildContext? itemContext;
Function(NewSaleItemModal newSaleItem) onNewSaleItem;
ProductItemWidget({
Key? key,
required this.onDelete,
required this.onNewSaleItem,
this.mainItems,
this.itemContext,
}) : super(key: key);
@override
State<ProductItemWidget> createState() => _ProductItemWidgetState();
}
These are the states
@override
void initState() {
super.initState();
print('Created with key: ${widget.key}');
}
@override
void didChangeDependencies() {
types = profileRepository.getConfigEnums(type: EnumType.discountType);
getAllProductNames();
super.didChangeDependencies();
}
@override
void dispose() {
super.dispose();
print('Disposed key: ${widget.key}');
selectedProductName = null;
selectedProduct = null;
selectedType = null;
_discountController.dispose();
_rateController.dispose();
_quantityController.dispose();
_unitController.dispose();
_amountController.dispose();
}
This is the where I added the key
@override
Widget build(BuildContext itemContext) {
return Form(
key: widget.key,
child: ..........
),
}
After adding first item, in console...
I/flutter (17380): Value key: [<0>]
I/flutter (17380): Created with key: [<0>]
I/flutter (17380): [NewSaleItemModal(productId: 23, batchId: 88, rate: 35567, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 35567)]
After adding second item, in console...
I/flutter (17380): Value key: [<1>]
I/flutter (17380): Created with key: [<1>]
I/flutter (17380): [NewSaleItemModal(productId: 23, batchId: 88, rate: 35567, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 35567), NewSaleItemModal(productId: 4, batchId: 69, rate: 1158, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 1158)]
Here is the video deleting the first item
When i delete the first item, in console...
I/flutter (17380): deleted 0 - value [<0>]
I/flutter (17380): [NewSaleItemModal(productId: 4, batchId: 69, rate: 1158, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 1158)]
I/flutter (17380): Value key: [<0>]
I/flutter (17380): Disposed key: [<1>]
Upvotes: 2
Views: 2328
Reputation: 1533
I also had the same problem in two my different projects, and sometimes even applied a "workaround" solution, like Visibility(visible: !_isDeleted, child: MyListViewItem(...)
but I always ended up with the same approach:
Use state management libraries. E.g. ScopedModel, Redux or Bloc. This appeared to be the only correct way for me.
In a few words:
model.removeItemAt(i)
. All listView items will be rebuilt properlyTextEditingController
s for all text fields and update the model each time user changes the textI hope it will help.
Upvotes: 0
Reputation: 2282
Just use UniqueKey()
instead of ValueKey(index)
It seems to have solved the problem for me.
Upvotes: 0
Reputation: 1285
hmm try using removeWhere to identify which item to be remove
saleItems.removeWhere((e)=> e.productId == saleItems[index].productId);
Upvotes: 0