Sumit Kumawat
Sumit Kumawat

Reputation: 125

When I'm trying to remove items from the listview using provider it removed last element from the list in flutter

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

Answers (2)

Alok
Alok

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

EdwynZN
EdwynZN

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

Related Questions