Reputation: 125
When I'm trying to remove item(like 0 index item)
from this listview
using provider it removed the last item from the list. while I'm deleting last element from the list successfully remove last item. I'm bit confusing why this kind of problem is happening to me.
Here I'm posting some code please check give your valuable suggestion. Also demonstrate on this video what issue is happening
Link:https://drive.google.com/file/d/1UYl8Z7vEj_tZCaYzqe0VqZL2iMla5nIZ/view?usp=sharing
Expected result: Whenever user press delete button then delete that particular row(item).
Delete method:- This is the delete method It'll be call when user press delete button from the list.
Future<void> acceptdeclinerequest(String requestStatus,int requestId) async{
String token = await CustomPreferences.getpreferences('token');
Map<String, String> requestHeaders;
if (token.isNotEmpty) {
requestHeaders = {
'Accept': 'application/json',
'Authorization': 'Bearer ' + token
};
} else {
requestHeaders = {
'Accept': 'application/json',
};
}
var reqdata = {
"request_id":requestId.toString(),
"status":requestStatus
};
print('accept request data is $reqdata');
try
{
final response =
await http.post(Connection.url + 'respond-place-request', headers: requestHeaders,body: reqdata);
if (response.statusCode == 200) {
Map<String, dynamic> responseJson = json.decode(response.body);
final existingProductIndex = _items.indexWhere((prod) => prod.id == requestId);
var existingProduct = _items[existingProductIndex];
_items.removeAt(existingProductIndex);
notifyListeners();
return responseJson;
} /*else if (response.statusCode == 500) {
return servererrorresponse;
}*/
} catch (exception) {
throw exception;
}
}
Main Widget class: This is the main widget class where I define Listview
widget. I've used provider to get data from api which is written in modal class to populate in Listview
and Listview child widgets
is in seprate class which is RequestWidgets
. In this class I've passed rowitems
data to show in listview
.
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
var connectionstatus;
var product;
var _isInit = true;
var _isLoading = false;
@override
void initState() {
super.initState();
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
if (_isInit) {
setState(() {
_isLoading = true;
});
Provider.of<BandRequestModal>(context).getBandRequestList().then((_) {
setState(() {
_isLoading = false;
});
});
}
_isInit = false;
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
connectionstatus = Provider.of<ConnectivityResult>(context);
product = Provider.of<BandRequestModal>(context, listen: false);
// getRequestData();
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
key: _scaffoldKey,
appBar: CustomAppbar(
_scaffoldKey, Constants.requests, 100.0, filterRecord),
endDrawer: MenuDrawer(),
body:
/*(connectionstatus == ConnectivityResult.wifi ||
connectionstatus == ConnectivityResult.mobile)
? */
Consumer<BandRequestModal>(builder: (context, modal, child) {
return !_isLoading
? Container(child: LayoutBuilder(builder:
(BuildContext context, BoxConstraints constraints) {
return Container(
height: constraints.maxHeight,
child: modal.item.length > 0
? ListView.builder(
padding:
EdgeInsets.only(top: 10.0, bottom: 0.0),
itemCount: modal.item.length,
shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, int i) {
return RequestWidgets(data: modal.item[i]);
})
: Center(
child: new Text(
Constants.norecordfound,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold),
),
),
// ],
// ),
);
}))
: Comman.loadingIndicator(Theme.of(context).primaryColor);
})
// : Comman.nointernetconnection(context)
// FutureBuilder<BandRequestModal>(
// future: Connection.bandRequestList(),
// builder: (context, snapshot) {
// switch (snapshot.connectionState)
// {
// case ConnectionState.none:
// break;
// case ConnectionState.waiting:
// return Comman.loadingIndicator(
// Theme.of(context).primaryColor);
// break;
// case ConnectionState.active:
// break;
// case ConnectionState.done:
// if (snapshot.hasError) {
// return Center(
// child: new Text(Constants.servererror),
// );
// }else if(snapshot.data==null){
// return Center(
// child: new Text(Constants.servererror),
// );
// } else if (snapshot.data.data.length == 0) {
// return Center(
// child: new Text(
// Constants.norecordfound,
// style: TextStyle(
// fontSize: 20.0, fontWeight: FontWeight.bold),
// ),
// );
// } else {
// return ListView.builder(
// padding:
// EdgeInsets.only(top: 10.0, bottom: 60.0),
// itemCount: snapshot.data.data.length,
// shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
// itemBuilder: (context, int i) {
// return RequestWidgets(data:snapshot.data.data[i]);
// });
// }
// break;
// }
// }):Comman.nointernetconnection(context)
));
}
Child widget class: This is the row items class of listview In this class we used many widgets to show place data.
class _RequestWidgetsState extends State<RequestWidgets> {
var getData;
var product;
@override
void initState() {
// TODO: implement initState
getData = widget.data;
super.initState();
}
@override
Widget build(BuildContext context) {
product = Provider.of<BandRequestModal>(context, listen: false);
return Container(
// alignment: Alignment.topLeft,
margin: EdgeInsets.only(top: 5.0),
child: ListTile(
// contentPadding: EdgeInsets.zero,
key: ObjectKey(getData),
leading: CircleAvatar(
radius: 30,
backgroundColor: Colors.transparent,
child: ClipOval(
child: (getData.placeDetails.image != null &&
getData.placeDetails.image != '')
? Image.network(
getData.placeDetails.image,
width: 90,
height: 90,
fit: BoxFit.cover,
)
: Image.asset(
Res.defaultImage,
width: 90,
height: 90,
fit: BoxFit.cover,
)),
),
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Text(getData.placeDetails.name,
style: TextStyle(
fontSize: 16.0,
fontFamily: 'Metropolis',
color: CustomColors.commentTitleColor))),
],
),
subtitle: Container(
margin: EdgeInsets.only(top: 1.0),
child: Column(children: <Widget>[
Container(
margin: EdgeInsets.only(top: 1.0),
child: Row(children: <Widget>[
Expanded(
child: Text(getData.placeDetails.address,
style: TextStyle(
fontSize: 15.0,
height: 1.2,
fontFamily: 'Metropolis',
color: CustomColors.commentSubtitleColor))),
]),
),
Container(
margin: EdgeInsets.only(top: 15.0, bottom: 15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[],
)),
Divider(
color: CustomColors.commentlineColor,
thickness: 0.8,
)
])),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
GestureDetector(
child: CircleAvatar(
radius: 20,
backgroundColor: Colors.green,
child: Icon(
Icons.check,
color: Colors.white,
),
),
onTap: () {
acceptrejectpopup('1');
// {
// print('accept data $data');
// Comman.hideLoading(context);
// Comman.showSnakBar(data['message'],context);
// });
},
),
SizedBox(
width: 15.0,
),
GestureDetector(
child: CircleAvatar(
backgroundColor: Colors.red,
child: Icon(
Icons.clear,
color: Colors.white,
),
),
onTap: () {
// Comman.showLoading(context);
acceptrejectpopup('0');
/*product.acceptdeclinerequest('0',getData.id.toString()).then((data){
print('decline data $data');
Comman.hideLoading(context);
Comman.showSnakBar(data['message'],context);
});*/
},
)
],
),
),
);
}
//accept and reject
void acceptRejectRequest(String requestStatus) async {
try {
var response =
await product.acceptdeclinerequest(requestStatus, getData.id);
if (response['status'] == Constants.status_true) {
Comman.hideLoading(context);
Comman.showSnakBar(response['message'], context);
// setState(() {});
} else {
Comman.hideLoading(context);
}
} catch (exception) {
Comman.hideLoading(context);
Comman.showSnakBar(Constants.servererror, context);
}
}
//request accept/reject popup
Future<void> acceptrejectpopup(String reqStatus) {
return showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Alert!',
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold)),
content: new Text(reqStatus == '1'
? Constants.reqAcceptmessage
: Constants.reqRejectemessage),
actions: <Widget>[
new FlatButton(
onPressed: () => Navigator.of(context).pop(),
child: new Text(Constants.notxt),
),
new FlatButton(
onPressed: () {
Navigator.of(context).pop();
Comman.showLoading(context);
acceptRejectRequest(reqStatus);
},
child: new Text(Constants.yestxt),
),
],
),
);
}
Upvotes: 4
Views: 2206
Reputation: 9018
The problem here I guess is, in your Child widget class
, since I can't see any requestId
of the selected card being passed to the acceptdeclinerequest()
.
Your acceptdeclinerequest()
expects two unique arguments to be passed when called:
String requestStatus
int requestId
If you look closely into the Child widget class, you are just passing requestStatus
. I wonder from where are you getting this getData.id
, and how is it identifying that some particular card is selected.
// look here, only requestStatus is being passed
onTap: () {
acceptrejectpopup('0');
}
// and here
onTap: () {
acceptrejectpopup('1');
}
And in your acceptRejectRequest
, you are only passing requestStatus
acceptRejectRequest(reqStatus);
And then you call your acceptdeclinerequest()
with this data
// machine is confused, where are we getting the getData.id
// it assumes the id as per it's need, hence the error
await product.acceptdeclinerequest(requestStatus, getData.id);
The machine is trying to figure out, which element you selected. Try to give the id from the selected card, and pass it to the method with correct getData.id
of that particular element.
Suggestion: Pass in your id
of the selected card when you are tapping on it, and then call your methods, and then pass it along to get the right requestId
and remove it. Let your methods acceptrejectpopup()
and acceptRejectRequest()
accept the id
of the selected item and then finally pass it to your acceptdeclinerequest()
// first step
onTap: () => acceptrejectpopup('0', your_card_reuqest_id);
// second step, pass data from the above popup method to acceptRejectRequest()
acceptRejectRequest(reqStatus, requestId);
//finally from acceptRejectRequest(reqStatus, requestId), pass it to the final method acceptdeclinerequest
acceptdeclinerequest(requestStatus, requestId);
Upvotes: 1
Reputation: 5611
The provider is working just fine, the problem is when the provider notify the consumer the ListView
updates the children, but the StatefulWidget
check they're the same type (They're all RequestWidget
) so they just update themselves (if you don't provide a key to the StatefulWidget
they will try to check if they're the same element and update via the didChangeDependencies
method), but you're updating the getData
var in initState (which will call only once) so even if the consumer updates the value won't. Try it like this
@override
void initState() {
// TODO: implement initState
//getData = widget.data; not here
super.initState();
}
@override
void didChangeDependencies() {
// TODO: implement initState
getData = widget.data; //update it here
super.didChangeDependencies();
}
Other option would be just to give a specific key when building your widget in the itemBuilder so when the consumer updates it changes them accordingly
return RequestWidgets(key: ValueKey(modal.item[i].id),data: modal.item[i]);
// Or some value unique for each item
Upvotes: 1