irongirl
irongirl

Reputation: 935

Refresh list after deleting an item - Flutter

I am trying to get the list to automatically refresh after the delete option on pop up menu is pressed. It will delete the selected item from a list of items called from an api. That item should immediately dissapear after delete is pressed on it.

API call that fills the list with api data:

  List data;

  @override
  void initState() {
    super.initState();
    this.getJsonData();
  }

  Future<String> getJsonData() async {
    var response = await http.get(
      Uri.encodeFull(url),
      headers: {"Accept": "application/json"},
    );

    var extractdata = json.decode(response.body);
    data = extractdata['levels'];
    levelsData = data;

    setState(
      () {
        var extractdata = json.decode(response.body);
        data = extractdata['levels'];
      },
    );
    return "Success";
  }

...

Api call that deletes:

  delete() async {
    String url = "http://31.183.125.253:8080/users";

    Map map = {
      'price': 1.23,
      'user_id': 'user2'
    };

    print(await apiRequest(url, map));
  }

  Future<String> apiRequest(String url, Map jsonMap) async {
    HttpClient httpClient = new HttpClient();
    HttpClientRequest request = await httpClient.deleteUrl(Uri.parse(url));
    request.headers.set('content-type', 'application/json');
    request.add(utf8.encode(json.encode(jsonMap)));
    HttpClientResponse response = await request.close();
    String statusCode = response.statusCode.toString();
    String reply = await response.transform(utf8.decoder).join();

    print(statusCode);

    httpClient.close();
    return reply;
  }

Expansion tile that stores the list from api call:

...

var levelsData = [];

  @override
  Widget build(BuildContext context) {
    List<dynamic> _getChildren() {
      List<Widget> children = [];
      levelsData.forEach(
        (element) {
            children.add(
              ListTile(
                title: Text(element['price'].toString(),
                trailing: PopUpMenu(
                  onDelete: () {
                    setState(() {
                      delete();
                    });
                  }))
            );}
      );
      return children;
    }
  }

...

Pop up menu:

class PopUpMenu extends StatelessWidget {
  VoidCallback onDelete;

  PopUpMenu({this.onDelete});

  void showMenuSelection(String value) {
    switch (value) {
      case 'Delete':
        onDelete();
        break;
      // Other cases for other menu options
    }
  }

I am able to delete the item selected to delete but the item doesnt dissapear from the list and it didnt show the changes of the list.

Upvotes: 6

Views: 12315

Answers (3)

x-DZ-Ax
x-DZ-Ax

Reputation: 322

I have an issue when deleting items from top and middle of the list view the index isn't in the right range import 'package:flutter/material.dart'; import 'package:flutter_tindercard/flutter_tindercard.dart';

class ExampleHomePage extends StatefulWidget {
  @override
  _ExampleHomePageState createState() => _ExampleHomePageState();
}

class _ExampleHomePageState extends State<ExampleHomePage>
    with TickerProviderStateMixin {
  List approved = [];
  List refused = [];

  List<String> welcomeImages = [
    "https://images.unsplash.com/photo-1631636176993-759dea1a1300?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw0fHx8ZW58MHx8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
    "https://images.unsplash.com/photo-1631634176568-f543af6a41de?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw3fHx8ZW58MHx8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
    "https://images.unsplash.com/photo-1631691971564-adf9419d904e?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxM3x8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
    "https://images.unsplash.com/photo-1631641906574-24adb8594649?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxMnx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
    "https://images.unsplash.com/photo-1593642702821-c8da6771f0c6?ixid=MnwxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHwxMXx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
    "https://images.unsplash.com/photo-1631621461675-e61a1f28d3d6?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw0NHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60"
  ];
  List<TinderCarder> cards = [];
  CardController controller = CardController(); //Use this to trigger swap.

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    for (int i = 0; i < welcomeImages.length; i++) {
      cards.add(TinderCarder(
          controller: controller,
          image: welcomeImages[i],
          onLeftPress: () {
            setState(() {
              print('index is: ' + i.toString());

              cards.removeAt(i);
              print('index is: ' + i.toString());
              print('list length: ' + cards.length.toString());
            });
          },
          onRightPress: () {
            setState(() {
              print('index is: ' + i.toString());

              cards.removeAt(i);
              print('index is: ' + i.toString());
              print('list length: ' + cards.length.toString());
            });
          }));
    }
    // cards = welcomeImages.map((element) {
    //   return TinderCarder(
    //     image: element,
    //     controller: controller,
    //     onLeftPress: () {
    //       setState(() {
    //         cards.removeAt(element.indexOf(element));
    //         print('index is: ' + "${element.indexOf(element)}");
    //         print('list length: ' + cards.length.toString());
    //       });
    //     },
    //     onRightPress: () {
    //       setState(() {
    //         cards.removeAt(element.indexOf(element));
    //         print('index is: ' + "${element.indexOf(element)}");
    //         print('list length: ' + cards.length.toString());
    //       });
    //     },
    //   );
    // }).toList();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        width: double.infinity,
        child: ListView.builder(
          shrinkWrap: true,
          key: Key(cards.length.toString()),
          physics: ScrollPhysics(),
          itemBuilder: (ctx, index) {
            return cards[index];
          },
          itemCount: cards.length,
        ),
      ),
    );
  }
}

class TinderCarder extends StatelessWidget {
  final String image;
  Function onLeftPress;
  Function onRightPress;
  var controller;

  TinderCarder(
      {required this.image,
      this.controller,
      required this.onLeftPress,
      required this.onRightPress});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 300,
      child: TinderSwapCard(
        orientation: AmassOrientation.BOTTOM,
        totalNum: 1,
        stackNum: 3,
        swipeEdge: 4.0,
        maxWidth: double.infinity,
        maxHeight: MediaQuery.of(context).size.width * 0.9,
        minWidth: MediaQuery.of(context).size.width * 0.8,
        minHeight: MediaQuery.of(context).size.width * 0.8,
        cardBuilder: (context, index) => Card(
          child: Column(
            children: [
              Image.network(
                image,
                width: double.infinity,
                height: 200,
                fit: BoxFit.cover,
              ),
              Text('Data')
            ],
          ),
        ),
        cardController: controller,
        swipeUpdateCallback: (DragUpdateDetails details, Alignment align) {
          /// Get swiping card's alignment
          if (align.x < 0) {
          } else if (align.x > 0) {}
        },
        swipeCompleteCallback: (CardSwipeOrientation orientation, int index) {
          print(orientation.toString());
          if (orientation == CardSwipeOrientation.LEFT) {
            print("Card is LEFT swiping");
            // print(welcomeImages.length);
            onLeftPress();
          } else if (orientation == CardSwipeOrientation.RIGHT) {
            print("Card is RIGHT swiping");
            // print(welcomeImages.length);
            onRightPress();
          }
        },
      ),
    );
  }
}

Error

======== Exception caught by animation library ===================================================== The following RangeError was thrown while notifying status listeners for AnimationController: RangeError (index): Invalid value: Not in inclusive range 0..3: 4

When the exception was thrown, this was the stack: #0 List.[] (dart:core-patch/growable_array.dart:254:60) #1 List.removeAt (dart:core-patch/growable_array.dart:23:22) #2 _ExampleHomePageState.initState.. (package:untitled/views/sweep_cards.dart:46:21) #3 State.setState (package:flutter/src/widgets/framework.dart:1088:30) #4 _ExampleHomePageState.initState. (package:untitled/views/sweep_cards.dart:43:13) ... The AnimationController notifying status listeners was: AnimationController#d4459(⏭ 1.000; paused)

Upvotes: 0

live-love
live-love

Reputation: 52554

You have to call setState and remove the item from your list.

     class _MyListViewState extends State<MyListView> {
          MyDB _myDB;
          List<MyItem> _myList;

        ...

      void getData() async {
        ...

        _myDB.getData().then((items) {
          setState(() {
            _myList = items;
          });
        });
      }

      @override
      void initState() {
        super.initState();
        getData();
      }

              @override
              Widget build(BuildContext context) {
                return (_myList== null || _myList.isEmpty)
                    ? Center(child: Text('Nothing to see...'))
                    : ListView.builder(
                        itemCount: _myList.length,
                        itemBuilder: (context, index) {
                          return

        ... onPress ...

                _myDB.deleteItem(_myList[index]).whenComplete(() {
                                                setState(() {
                                                  _myList.removeAt(index);
                                                });
                                              });

Upvotes: 5

DevTard
DevTard

Reputation: 480

Flutter should automatically update to reflect changes to datasources. However, this is only applied after calling:

setState((){

});

So that should be run after you delete the item from the list.

Upvotes: 5

Related Questions