Когда я пытаюсь удалить элементы из списка с помощью провайдера, он удалил последний элемент из списка во флаттере - PullRequest
2 голосов
/ 03 августа 2020

Когда я пытаюсь удалить item(like 0 index item) из этого listview с помощью провайдера, он удалил последний элемент из списка. пока я удаляю последний элемент из списка успешно удаляю последний элемент. Я немного не понимаю, почему у меня возникает такая проблема.

Здесь я публикую код, пожалуйста, проверьте, дайте свое ценное предложение. Также продемонстрируйте на этом видео, что происходит.

Ссылка: https://drive.google.com/file/d/1UYl8Z7vEj_tZCaYzqe0VqZL2iMla5nIZ/view?usp=sharing

Ожидаемый результат: Каждый раз, когда пользователь нажимает кнопку удаления, удаляйте этот конкретный row (item).

Метод удаления: - Это метод удаления. Он будет вызван, когда пользователь нажмет кнопку удаления из списка.

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;
    }
  }

Главный класс виджета: Это основной класс виджета, в котором я определяю виджет Listview. Я использовал провайдера для получения данных из api, который записан в модальном классе для заполнения Listview, а Listview child widgets находится в отдельном классе, который равен RequestWidgets. В этом классе я передал rowitems данных для отображения в 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)
            ));
  }

Класс дочернего виджета: Это класс элементов строки для listview В этом классе мы использовали множество виджетов для отображения данных о месте.

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),
          ),
        ],
      ),
    );
  }

Ответы [ 2 ]

1 голос
/ 03 августа 2020

Проблема здесь, я полагаю, в вашем Child widget class, поскольку я не вижу, чтобы requestId выбранной карты передавалась в acceptdeclinerequest().

Ваш acceptdeclinerequest() ожидает два уникальные аргументы, передаваемые при вызове:

  • String requestStatus
  • int requestId

Если вы внимательно посмотрите на дочерний класс виджетов , вы просто проходите requestStatus. Интересно, откуда вы берете этот getData.id и как он определяет, что выбрана конкретная карта.

// look here, only requestStatus is being passed
onTap: () {
    acceptrejectpopup('0');
 }

// and here
onTap: () {
   acceptrejectpopup('1');
}

А в вашем acceptRejectRequest вы передаете только requestStatus

acceptRejectRequest(reqStatus);

И затем вы вызываете свой acceptdeclinerequest() с этими данными

// 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);

Машина пытается выяснить, какой элемент вы выбрали. Попробуйте указать идентификатор выбранной карты и передать его методу с правильным getData.id этого конкретного элемента.

Предложение: Передайте свой id выбранной карты когда вы нажимаете на него, а затем вызываете свои методы, а затем передаете его, чтобы получить правильный requestId и удалить его. Пусть ваши методы acceptrejectpopup() и acceptRejectRequest() принимают id выбранного элемента, а затем, наконец, передают его вашему 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);
1 голос
/ 03 августа 2020

Провайдер работает нормально, проблема в том, что провайдер уведомляет потребителя, что ListView обновляет дочерние элементы, но StatefulWidget проверяет, что они одного типа (все они RequestWidget), поэтому они просто обновите себя (если вы не предоставите ключ для StatefulWidget, они попытаются проверить, являются ли они одним и тем же элементом, и обновить их с помощью метода didChangeDependencies), но вы обновляете getData var в initState (который будет вызывать только один раз), поэтому, даже если потребитель обновит значение, не будет. Попробуйте это так:

@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();
}

Другой вариант - просто указать конкретный ключ c при создании вашего виджета в itemBuilder, чтобы при обновлении потребителя он изменил их соответственно

return RequestWidgets(key: ValueKey(modal.item[i].id),data: modal.item[i]);

// Or some value unique for each item
...