45

I'm displaying a list of users in a table, each row has a checkbox to select the user and the checkbox value is the user's ID. The selected IDs are in turn displayed in a span below the table.

How can I select all checkboxes and deselect all checkboxes on the click of a "select all" checkbox that I have in the header of my table? Do I interact with the DOM to do this or through the vue object, I'm thinking it should be the latter but quite unsure how to approach what appears to be an easy task?! Any help would be appreciated!

HTML

<div id="app">
    <h4>Users</h4>
    <div>
        <table>
            <tr>
                <th>Name</th>
                <th>Select <input type="checkbox" @click="selectAll"></th>
            </tr>
            <tr v-for="user in users">
                <td>{{ user.name }}</td>
                <td><input type="checkbox" v-model="selected" value="{{ user.id }}"></td>
            </tr>
        </table>
    </div>

    <span>Selected Ids: {{ selected| json }}</span>
</div>

Javascript/Vuejs

new Vue({
    el: '#app',
    data: {
        users: [ 
            { "id": "1", "name": "Shad Jast", "email": "[email protected]", 
            { "id": "2", "name": "Duane Metz", "email": "[email protected]"}, 
            { "id": "3", "name": "Myah Kris", "email": "[email protected]"}, 
            { "id": "4", "name": "Dr. Kamron Wunsch", "email": "[email protected]"}, 
            { "id": "5", "name": "Brendon Rogahn", "email": "[email protected]"}
        ],
        selected: []
    },
    methods: {
        selectAll: function() {
            // ?
        }
    }
})

10 Answers 10

85

I think @Jeremy's answer is cleaner way, but it require for checked property on each user object which is makes no sense if the data come from an API request.

Here is working and cleaner code for select/deselect all rows without having to add checked property on user object:

new Vue({
    el: '#app',
    data: {
        users: [ 
            { "id": "1", "name": "Shad Jast", "email": "[email protected]" },
            { "id": "2", "name": "Duane Metz", "email": "[email protected]" }, 
            { "id": "3", "name": "Myah Kris", "email": "[email protected]" }, 
            { "id": "4", "name": "Dr. Kamron Wunsch", "email": "[email protected]" }
        ],
        selected: []
    },
    computed: {
        selectAll: {
            get: function () {
                return this.users ? this.selected.length == this.users.length : false;
            },
            set: function (value) {
                var selected = [];

                if (value) {
                    this.users.forEach(function (user) {
                        selected.push(user.id);
                    });
                }

                this.selected = selected;
            }
        }
    }
});
<script src="https://cdn.jsdelivr.net/vue/latest/vue.js"></script>

<div id="app">
<h4>User</h4>
<div>
    <table>
        <tr>
            <th><input type="checkbox" v-model="selectAll"></th>
            <th align="left">Name</th>
        </tr>
        <tr v-for="user in users">
            <td>
                <input type="checkbox" v-model="selected" :value="user.id" number>
            </td>
            <td>{{ user.name }}</td>
        </tr>
    </table>
</div>
</div>

Please note that the number attribute on row's checkbox is required, otherwise you have to push the user id selectAll method as a string, like selected.push(user.id.toString());

Sign up to request clarification or add additional context in comments.

1 Comment

Whe can use the object as a key too. codepen.io/anon/pen/RJErOV?editors=1111
13

Adding my own answer as edits on the answer by nhydock weren't accepted (I think?).

Solution selects and selects all.

HTML

<div id="app">
    <h4>User</h4>
        <div>
            <table>
                <tr>
                    <th>Name</th>
                    <th>Select <input type="checkbox" @click="selectAll" v-model="allSelected"></th>
                </tr>
                <tr v-for="user in users">
                    <td>{{ user.name }}</td>
                    <td><input type="checkbox" v-model="userIds" value="{{ user.id }}"></td>
                </tr>
            </table>
        </div>

        <span>Selected Ids: {{ userIds | json }}</span>
</div>

Javascript/Vuejs

new Vue({
    el: '#app',
    data: {
        users: [ 
            { "id": "1", "name": "Shad Jast", "email": "[email protected]"}, 
            { "id": "2", "name": "Duane Metz", "email": "[email protected]"}, 
            { "id": "3", "name": "Myah Kris", "email": "[email protected]"}, 
            { "id": "4", "name": "Dr. Kamron Wunsch", "email": "[email protected]"}, 
            { "id": "5", "name": "Brendon Rogahn", "email": "[email protected]"}
        ],
        selected: [],
        allSelected: false,
        userIds: []
    },
    methods: {
        selectAll: function() {
            this.userIds = [];

            if (!this.allSelected) {
                for (user in this.users) {
                    this.userIds.push(this.users[user].id);
                }
            }
        },
    }
})

Working fiddle: https://jsfiddle.net/okv0rgrk/3747/

3 Comments

ISSUE: 1)select all; 2)Unselect one item. the SelectAll checkbox should become unselected.
@Sigma Good catch, I added a fix to the fiddle, perhaps not a great solution but it works. Feel free to post your own solution.
In method selectAll it should be "if(this.allSelected)" instead of "if(!this.allSelected)". There is no need to use ! .
6

Basically the same answer as @Rifki, but checks if each element exists in both, rather than just the length.

new Vue({
  el: '#app',
  data: {
    users: [{
        "id": "1",
        "name": "Shad Jast",
        "email": "[email protected]"
      },
      {
        "id": "2",
        "name": "Duane Metz",
        "email": "[email protected]"
      },
      {
        "id": "3",
        "name": "Myah Kris",
        "email": "[email protected]"
      },
      {
        "id": "4",
        "name": "Dr. Kamron Wunsch",
        "email": "[email protected]"
      }
    ],
    selected: []
  },
  computed: {
    selectAll: {
      get() {
        if (this.users && this.users.length > 0) { // A users array exists with at least one item
          let allChecked = true;

          for (const user of this.users) {
            if (!this.selected.includes(user.id)) {
              allChecked = false; // If even one is not included in array
            }
            
            // Break out of loop if mismatch already found
            if(!allChecked) break;
          }

          return allChecked;
        }

        return false;
      },
      set(value) {
        const checked = [];

        if (value) {
          this.users.forEach((user) => {
            checked.push(user.id);
          });
        }

        this.selected = checked;
      }
    },
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <h4>User</h4>
  <div>
    <table>
      <tr>
        <th><input type="checkbox" v-model="selectAll"></th>
        <th align="left">Name</th>
      </tr>
      <tr v-for="user in users">
        <td>
          <input type="checkbox" v-model="selected" :value="user.id" number>
        </td>
        <td>{{ user.name }}</td>
      </tr>
    </table>
  </div>
</div>

2 Comments

While deselecting the parent checkbox, all the child checkbox are unselected. Can you update your answer Vue version: "^2.6.10",
Maybe I'm misunderstanding what you're saying, but that's the desired result for the question asked.
5

How about my answer, with less properties, easy to understand?

new Vue({
  el: '#app',
  data: {
    users: [{
      "id": "1",
      "name": "Shad Jast",
      "email": "[email protected]",
      'checked': false
    }, {
      "id": "2",
      "name": "Duane Metz",
      "email": "[email protected]",
      'checked': false
    }, {
      "id": "3",
      "name": "Myah Kris",
      "email": "[email protected]",
      'checked': false
    }, {
      "id": "4",
      "name": "Dr. Kamron Wunsch",
      "email": "[email protected]",
      'checked': false
    }, ],

  },
  computed: {
    selectAll: function() {
      return this.users.every(function(user){
        return user.checked;
      });
    }
  },
  methods: {
    toggleSelect: function() {
      var select = this.selectAll;
      this.users.forEach(function(user) {

        user.checked = !select;

      });
      this.selectAll = !select;
    },

  }
});
<script src="https://cdn.jsdelivr.net/vue/latest/vue.js"></script>

<div id="app">
  <h4>User</h4>
  <div>
    <table>
      <tr>
        <th>Name</th>
        <th>Select
          <input type="checkbox" @click="toggleSelect" :checked="selectAll">
        </th>
      </tr>
      <tr v-for="user in users">
        <td>{{ user.name }}</td>
        <td>
          <input type="checkbox" v-model="user.checked">
        </td>
      </tr>
    </table>
  </div>

</div>

2 Comments

I guess it relies on each data item having 'checked': false?
this.selectAll = !select; is unnecessary, 'cause this.selectAll will always rely on whether if all users' checked property have been checked~
4

I want to thank everyone for sharing their solutions. It has been a big help with learning. A developer on gitter helped me to add a Default checkbox that will select a subset of the array that has a property called "default" set to true.

here is the code:

// based on https://jsfiddle.net/okv0rgrk/3747/

new Vue({
    el: '#app',
    data: {
        selected: [],
        defaultSelects: [],
        selectsArray: [ 

            {id: 'automotive', name: 'Automotive', class: 'industry', default: false},

            {id: 'beauty', name: 'Beauty', class: 'industry', default: true},

            {id: 'branding', name: 'Branding', class: 'industry', default: true},

            {id: 'btob', name: 'B to B', class: 'industry', default: false}
        ],
        selected: [],
    },
    computed: {
      defaultChecked: {
        get () {
          let defaults = this.selectsArray.filter(item => item.default).map(item => item.id)
          const hasAllItems = (baseArr, haystack) => haystack.every(item => baseArr.includes(item))
          const hasSameItems = (baseArr, haystack) => hasAllItems(baseArr, haystack) && hasAllItems(haystack, baseArr)
          return hasSameItems(this.selected, defaults)
        },
        set (value) {
          this.selected = []

          if (value) {
            this.selectsArray.forEach((select) => {
              if (select.default) {
                this.selected.push(select.id)
              }
            });
          }
        }
      }, // END defaultChecked
      selectAll: {
        get () {
          return this.selected.length === this.selectsArray.length
        },
        set (value) {
          this.selected = []

          if (value) {
            this.selectsArray.forEach((select) => {
              this.selected.push(select.id)
            })
          }
        }
      }, // END selectAll
    }
})
<script src="https://cdn.jsdelivr.net/vue/latest/vue.js"></script>

<div id="app">
          
<div id="default-settings">

<label class="pref-button"><input type="checkbox" v-model="defaultChecked"><span>Default</span></label>

<label class="pref-button"><input type="checkbox" v-model="selectAll"><span>Select All</span></label>

</div>    
          
<label :for="select.id" v-for="select in selectsArray" v-bind:key="select.id"><input :value="select.id" v-model="selected" :id="select.id" :sector="select.id" :class="select.class" :default="select.default" type="checkbox">{{ select.name }}</label>

<span>Selected Ids: {{ selected }}</span>
  
</div>

Comments

3

All you have to do is add your users, using their ID since that's how you're referencing their values with the checkbox, and add them into your selected array.

selectAll: function() {
    this.selected = [];
    for (user in this.users) {
        this.selected.push(this.users[user].id);
    }
}

Running JSFiddle

4 Comments

thanks for your reply. That works just great for selecting all the values, but how about deselecting?
I'm guessing I can check if the selected all is true or false and remove all from selected if false? Going to try in your fiddle.
Woo! Got it working, I'm going to update your answer a little, hope that's okay? Have updated your fiddle with the solution. Thanks for your help buddy
Good answer nhydock.
2

Here is the simplest solution with v-models and computed only. No additional arrays, @click, :checked needed.

HTML

<div id="app">
   <input type="checkbox" v-model="allSelected"> Select All

   <ul>
      <li v-for="user in users">
         <input type="checkbox" v-model="user.selected"> {{ user.name }}
      </li>
   </ul>

   <button @click="getSelectedUsers">Get Selected Users</button>
</div>

JS

new Vue({
  el: "#app",
  data: {
    users: [
      {
        id: 1,
        name: "Alda Myrrhine",
        selected: false,
      },
      {
        id: 2,
        name: "Amrita Rabi",
        selected: false,
      },
      {
        id: 3,
        name: "Ruza Alannah",
        selected: false,
      },
    ]
  },
  computed: {
    allSelected: {
      set (selected) {
        this.users.forEach(function (user) {
          user.selected = selected;
        });
      },
      get () {
        return this.users.every(function (user) {
          return user.selected;
        });
      }
    }
  },
  methods: {
    getSelectedUsers () {
      let users = this.users.filter((user) => {
        return user.selected;
      });
      
      console.log(users);
    }
  }
})

Note that you need property user.selected to exist from beginning (for example if you load data from API or elsewhere).

Working example: https://jsfiddle.net/y8gujf2p/

Comments

1

i think this could be a little bit easier.

selectAll: function (isSelected) {
  if (!isSelected) {
    this.ids = []
    return false
  }
  if (isSelected) {
    this.rows.map(item => this.ids.push(item.id))
  }
}

Comments

1

I have a more simple solution as following and it has all you want. The real data should be put into a map indexed the name as the label of checkbox for future easy to access.

<template>
  <div align="left">
    <div>
      <input type="checkbox" id="all" :checked="allNamesSelected" @click="selectAll()">
      <label for="all">All</label>
    </div>
    <div v-for="(name) in names" :key="name">
      <input type="checkbox" :id="name" :value="name" :check="isChecked(name)" v-model="selectedNames">
      <label :for="name">{{name}}</label>
    </div>
  </div>
</template>

<script>
export default {
    data() {
        return {
            names: ['Automotive', 'Beauty', 'Branding', 'B to B'],
            selectedNames: [],
        }; 
    },
    computed: {
        allNamesSelected() {
            return this.names.length == this.selectedNames.length;
        },
    },
    methods: {
        selectAll() {
            if (this.allNamesSelected) {
                this.selectedNames = [];
            } else {
                this.selectedNames = this.names.slice();
            }
        },
        isChecked(name) {
            return this.selectedNames.includes(name);
        }
    }
}
</script>

Comments

0

Often there is no need to display selected IDs below the table. In such cases the above code can be simplified to:

HTML

<div id="app">
    <h4>Users</h4>
    <div>
        <table>
            <tr>
                <th>Name</th>
                <th>Select <input type="checkbox" v-model="selectAll"></th>
            </tr>
            <tr v-for="user in users">
                <td>{{ user.name }}</td>
                <td><input type="checkbox" :value="user.id" :checked="selectAll"></td>
            </tr>
        </table>
    </div>
</div>

VueJs

new Vue({
    el: '#app',
    data: {
        users: [ 
            { "id": "1", "name": "Shad Jast", "email": "[email protected]"}, 
            { "id": "2", "name": "Duane Metz", "email": "[email protected]"}, 
            { "id": "3", "name": "Myah Kris", "email": "[email protected]"}, 
            { "id": "4", "name": "Dr. Kamron Wunsch", "email": "[email protected]"}, 
            { "id": "5", "name": "Brendon Rogahn", "email": "[email protected]"}
        ],
        selectAll: false
    }
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.