Removing and Filtering

Habits change: one you've stopped doing should go, and on a busy day, you'll want to see only what's left to do. In this exercise, each habit gets a Remove button, and the list gets a filter.

Removing. The button is in HabitItem, but the habits are in App.vue, so it's just like the checkbox: the component sends an event, this time remove, and the parent does the work. A component can send several events, and defineEmits lists them all:

const emit = defineEmits(["toggle", "remove"]);
<button @click="emit('remove', habit.id)">Remove</button>

The button goes after the label, not inside it, because the label belongs to the checkbox. In App.vue, remove(id) keeps all the habits except that one, with filter(). It makes a new array, which goes into habits.value, as in the lesson State and Events:

function remove(id) {
    habits.value = habits.value.filter((habit) => habit.id !== id);
}

Filtering. Above the list, a drop-down list (a select) chooses what the list shows: all the habits, only the ones still to do, or only the done ones. v-model puts its value into the ref filter, and the list shows a computed value made from habits and filter. (The ref filter and the array method filter() only share a name.)

<label class="filter">
    Show
    <select v-model="filter">
        <option value="all">All</option>
        <option value="todo">To do</option>
        <option value="done">Done</option>
    </select>
</label>
const filter = ref("all");

const shownHabits = computed(() => {
    if (filter.value === "todo") {
        return habits.value.filter((habit) => !habit.done);
    }
    if (filter.value === "done") {
        return habits.value.filter((habit) => habit.done);
    }
    return habits.value;
});

The progress still counts all the habits, from habits. Only v-for goes through shownHabits. With the filter on To do, a habit you check off leaves the list at once, because it's no longer in shownHabits.

Instructions

  1. In HabitItem.vue, add "remove" to defineEmits and put the button from above after the label. In App.vue, write remove(id) and add @remove="remove" to HabitItem. Remove a habit: it disappears, and the progress counts one habit fewer.

  2. Add the ref filter and the computed value shownHabits from above, put the label with the select above the list, and change v-for so that it goes through shownHabits. Check a habit off and choose To do: the habit isn't in the list. Choose Done, and it's the only one there.