skip to Main Content

I am trying to create a Todo App in Flutter, and in my app bar I have a navigation drawer. Inside the navigation drawer I have three different filtering options: ‘All’, ‘Done’ and ‘Undone’. When the user presses on let’s say ‘Done’, then all the todo items that have been checked as ‘Done’ should be displayed on the page.

Every single todo item is stored inside a list called ‘TodoItemsList’. So far, I am displaying all the todo items using a Listview.builder:

   body: ListView.builder(
 itemCount: TodoItemsList.length,
 itemBuilder: (context, index) {
   return getCard(TodoItemsList[index]);
 },

),

And so far, I have managed to add all the checked items in a list called ‘filterDone’, and all the unchecked items in a list called ‘filterUndone’. I also have a filter variable that changes value whenever a user presses on ‘All’, ‘Done’, or ‘Undone’:

My problem: I don’t know how to actually make the filtering buttons in the navigation drawer work. I tried to add if/else statements that checks the value of the filter variable to my Listview.builder, in order to return the correct list:

 body: ListView.builder(
  itemCount: TodoItemsList.length,
  itemBuilder: (context, index) {
    
    if(filter == 'All') {
      return getCard(TodoItemsList[index]);
    } else if (filter == 'Done') {
       return getCard(filterDone[index]);
    } else if (filter == 'Undone') {
       return getCard(filterUndone[index]); 
    } else {
      return Container();
    }
    
  },

),

However, this isn’t working and I understand that it is a dead code because I have no setState or rebuild function anywhere, but I don’t know where to add it. I tried to wrap the return getCard() inside a setState function like so:

if(filter == 'All') {
      setState(() {
        return getCard(TodoItemsList[index]);
      });

.. but it just returns the error message: The return type ‘Widget’ isn’t a ‘void’, as required by the closure’s context.

I’d appreciate the help and I can add more code to my question if anything is unclear. Right now my code is not modular enough to paste everything into the question.

2

Answers


  1. try creating a state variable first, such as currentList. Then you may use setState to assign each list to the variable based on your filter.

    ex.

    var currentList;
    
    if(filter == 'All') {
          setState(() {
            currentList = todoItemsList;
          });
          ...
          ...
    
          return getCard(currentList[index]);
    
    Login or Signup to reply.
  2. Of course, the best thing would be to use some sort of state management like Bloc, Provider, etc. depending on how hard wired your widgets are built. But also with classic setState this should not be a problem. This would be an easy way to do it:

    You can define yourself an enum to find out the current filter:

    enum Filter {
      All,
      Done,
      Undone,
    }
    

    You need a variable to find out the current filter and of course your datasets. In my case TodoItems consist only of a title and a boolean isChecked.

        Filter currentFilter = Filter.All;
        List<TodoItem> todoItems = [
        TodoItem("Todo Item 1", false),
        TodoItem("Todo Item 2", false),
        TodoItem("Todo Item 3", true),
        TodoItem("Todo Item 4", false),
        TodoItem("Todo Item 5", true),
        TodoItem("Todo Item 6", false),
        ];
    

    Also I define a second list filteredItems, which I will pass to the ListView later.

    List<TodoItem> filteredItems = [];
    

    Every time you press on a ListTile in the Drawer, I change the filter and get the matching records, which I then pass to the filteredItems List.

    void filterItems(Filter filter) {
        currentFilter = filter;
        switch (currentFilter) {
          case Filter.All:
            filteredItems = List.from(todoItems);
            break;
          case Filter.Done:
            filteredItems =
                todoItems.where((element) => element.isSelected).toList();
    
            break;
          case Filter.Undone:
            filteredItems =
                todoItems.where((element) => !element.isSelected).toList();
    
            break;
          default:
        }
        setState(() {});
      }
    }
    

    Full example on dartpad: https://dartpad.dev/?id=4c230e7cd75eb0b6bbeb84f7eaa46583

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search