1

I actually have a list with a remove button. Once pressed, it shows a dialog to be sure that we want to delete the item. Once deleted, i would like that the item disappears from the UI without rebuilding the full list. I just need that the item concerned be deleted. So it should not do any loading process.

Actually, the list is fully rebuilt. enter image description here I was using a statelesswidget, now it is a statefull widget. I thought it would help me..

Source code :

class ListGroupsOfUser extends StatefulWidget {
  final String title;
  ListGroupsOfUser({
    required this.emailParameter,
    required this.title,
    Key? key,
  }) : super(key: key);
  final String emailParameter;

  @override
  _ListItem createState() => _ListItem();
}

class _ListItem extends State<ListGroupsOfUser> {
  @override
  Widget build(BuildContext context) => Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SafeArea(
          child: Column(children: [
        // Padding(padding: const EdgeInsets.all(5)),
        Padding(
          padding: const EdgeInsets.only(top: 10, bottom: 8),
          child: Badge(
            toAnimate: true,
            animationDuration: Duration(seconds: 2),
            shape: BadgeShape.square,
            badgeColor: Colors.indigo,
            borderRadius: BorderRadius.circular(8),
            badgeContent: Text("Utilisateur : " + widget.emailParameter, style: TextStyle(color: Colors.white, fontSize: 18)),
          ),
        ),
        Expanded(
            // padding: EdgeInsets.all(16),
            child: FutureBuilder<List<User>>(
                future: UsersAndGroupsService.fetchGroupsOfUser(widget.emailParameter),
                builder: (context, snapshot) {
                  if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) {
                    final result = snapshot.data!;

                    return ListView.separated(
                      separatorBuilder: (BuildContext context, int index) => const Divider(),
                      itemCount: result.length,
                      itemBuilder: (context, index) {
                        return Padding(
                          padding: const EdgeInsets.only(left: 10, right: 10),
                          child: Card(
                            child: Column(
                              children: <Widget>[
                                ListTile(
                                  title: Text(result[index].name),
                                  leading: Icon(Icons.group),
                                  trailing: IconButton(
                                    icon: Icon(Icons.clear, color: Colors.red),
                                    onPressed: () {
                                      confirm(context, "Suppression", "Voulez-vous vraiment supprimer le groupe " + result[index].name + " de l'utilisateur ?", result, index);
                                    },
                                  ),
                                ),
                              ],
                            ),
                          ),
                        );
                      },
                    );
                  } else {
                    return Center(child: CircularProgressIndicator());
                  }
                }))
      ])));

  _confirmResult(bool isYes, BuildContext context, List<User> result, index) {
    if (isYes) {
      print("HELL YES!");
      print(result.length);
      setState(() {
        result.removeAt(index);
      });

      print(result.length);
      // print(userInputController.text);
      // _write();
      Navigator.pop(context);
    } else {
      print("HELL NO!");
      // print(input);

      Navigator.pop(context);
    }
  }

  confirm(BuildContext context, String title, String subTitle, List<User> result, index) {
    return Dialogs.materialDialog(msgStyle: TextStyle(fontSize: 16), msg: subTitle, title: title, color: Colors.indigo, context: context, actions: [
      IconsOutlineButton(
        onPressed: () {
          _confirmResult(false, context, result, index);
        },
        text: 'Cancel',
        iconData: Icons.cancel_outlined,
        textStyle: TextStyle(color: Colors.grey),
        iconColor: Colors.grey,
      ),
      IconsButton(
        onPressed: () {
          _confirmResult(true, context, result, index);
        },
        text: 'Delete',
        iconData: Icons.delete,
        color: Colors.red,
        textStyle: TextStyle(color: Colors.white),
        iconColor: Colors.white,
      ),
    ]);
  }
}

Update after answer :

late Future<List<User>> result2;

  @override
  void initState() {
    super.initState();
    result2 = getUserList();
  }

  Future<List<User>> getUserList() async {
    return await UsersAndGroupsService.fetchGroupsOfUser(widget.emailParameter);
  }

...

child: FutureBuilder(
  future: result2,
  builder: (context, snapshot) {
    if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) {
    Don't know if updates needed after that

Update 2 :

List<User> result = [];

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

  getUserList() async {
    result = await UsersAndGroupsService.fetchGroupsOfUser(widget.emailParameter);
  }

...
Expanded(
            // padding: EdgeInsets.all(16),
            child: result == null
                ? CircularProgressIndicator()
                : ListView.separated(
                    separatorBuilder: (BuildContext context, int index) => const Divider(),
                    itemCount: result.length,
                    itemBuilder: (context, index) {

result == null : the operand can't be null, so the condition is always false. And something strange, i go on the page, results are loaded, but if i press back button and i go again on the page, no results are loaded, it's stays empty -> List? result solved the error message A Gif to show the problem. The data comes only when i do CTRL+S on VSC xD enter image description here

Kévin
  • 497
  • 10
  • 37

1 Answers1

2

setState will rebuild your entire build method so your FutureBuilder will reload again that is why it's loading again.

Remove FutureBuilder and call UsersAndGroupsService.fetchGroupsOfUser(widget.emailParameter) in initState.

When data will come initialise list and use that list.

Code:

List<User> result;

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

getUserList() async {
  result = await UsersAndGroupsService.fetchGroupsOfUser(widget.emailParameter);
  setState(() {});
}

in build method

result == null ? CircularProgressIndicator() : Listview()

Now you can execute your code with peacefully :)

Priyesh
  • 1,266
  • 5
  • 17
  • True, and he needs to assign Key for his tiles in a list to prevent unwanted behaviour after item deletion. – Simon Sot May 26 '21 at 10:45
  • @Priyesh Thanks for the response, but i don't arrive to apply it, i tested other things too, but i don't understand how i should modify my FutureBuilder.. I update my post – Kévin May 26 '21 at 12:10
  • I updated with a second edit, i think i understood your answer, but i have a strange behaviour – Kévin May 26 '21 at 12:47
  • @SimonSot For what you said, can you explain why should i do that : `key: new Key(index.toString()),` , what type of unwanted behaviour could i have ? – Kévin May 26 '21 at 12:53
  • @Kévin for example lets say you can select your tiles and change their state (for example you change color to indicate that item is selected). After you delete a tile from a list without a unique Key your state will be shifted, deleted tile will be gone but states from other tiles will shift and you will see in this example highlighted another tile that you did not select. – Simon Sot May 26 '21 at 13:09
  • @SimonSot Ok i understand thanks ! I updated my post again to show a gif with the problem of display – Kévin May 26 '21 at 13:12
  • @Kévin try to replace `List result = []` on `late List result;` – Simon Sot May 26 '21 at 13:21
  • @SimonSot I already did it ;) But was not resolving the == null, `List? result;` is resolving the null error – Kévin May 26 '21 at 13:22
  • I finally found the problem, thanks to this : https://stackoverflow.com/questions/60863575/list-not-being-updated-when-list-updated-from-initstate We have to set this because the widget is already build when the data arrives ! `setState(() {});` I will update your answer (i cannot queue full) in the getUserList, add at the end : setState(() {}); – Kévin May 26 '21 at 17:50
  • Thanks for your help @SimonSot. Keep growing Kévin. – Priyesh May 27 '21 at 05:41