Image

build-a-gmail-clone-with-vue-3

3 min read
Last update: December 19, 2021

Multi-select with Reactive Sets

For the starting code for this lesson, switch to branch: https://github.com/Code-Pop/build-gmail-clone-with-vue-3/tree/video-11-start

We’ve had these checkboxes sitting to the left of each email for a while, but we haven’t done anything with them. In the next four lessons, we’re going to connect them to app-wide state, add a select-all checkbox at the top, then add a Bulk Action Bar and apply those actions to the checked boxes.

For this lesson, we’re going to use a Set and a Reactive object to track which checkboxes are checked.

We’ll want an emailSelection object which can toggle an email as selected, and has a list of selected emails. We might use it something like this - note that we have the @click event and the :checked binding both connected to the emailSelection object.

<table class="email-table">
    <tbody>
        <tr v-for...>
            <td>
                <input type="checkbox" :checked="emailSelection.emails.has(email)" @click="emailSelection.toggle(email)" />
            </td>
            ...
        </tr>
    </tbody>
</table>

A naive implementation of this would use an Array, and then implement some extra code for has. Here’s some pseudocode for what we’ll be putting in the setup function.

let emailSelection = {
selected: [],
toggle(email) {
if(emailSelected) {
removeSelection()
} else {
addSelection()
}
}
}

emailSeIected and removeSelection() would each take multiple lines, or at least one longer line, to implement if we used in Array… but if we use a Set, then they both come built-in.

let selected = new Set()
let emailSelection = {
selected,
toggle(email){
if(selected.has(email)) {
selected.delete(email)
} else {
selected.add(email)
}
}
}

has , delete, and add do exactly what you’d expect.

Now let’s test this. We’ll add a console.log in our toggle function, and then display the size of the set in the template.

{{emailSelection.emails.size}} emails selected
<table class="mail-table">
    <!-- ... -->
</table>

However, we have a problem. The console.log shows the correct number of checkboxes selected, but template still says there are 0 selected.

That’s because the selected set referenced by the template is not changing when the email is toggled. Let’s fix this by making it reactive, using the new Vue 3 Reactivity API.

import { reactive } from 'vue';
//...
setup() {
//...
let selected = reactive(new Set())
let emailSelection = {
selected,
toggle(email){
if(selected.has(email)) {
selected.delete(email)
} else {
selected.add(email)
}
}
}

return {
emailSelection,
...
}
}

If you want to know more about reactive, I recommend the VueMastery series on Vue 3 Essentials, especially video 2 and 5.

And now our selection is working! In the next lesson we’ll go over how to share this data over multiple components in different parts of your app.

For the ending code for this lesson, switch to branch: https://github.com/Code-Pop/build-gmail-clone-with-vue-3/tree/video-11-end

Jeffrey teaches an 8-week beginning Vue course with guaranteed results. Built on top of the VueMastery curriculum, with extra hands-on assignments and personal attention. You can find it here.