Is there a way to gather selected checkboxes from all child checkbox components in vue?

I have a unique setup where my table rows are generated by child components, each containing a checkbox. I am looking for a way to retrieve all the checked checkboxes at once without using two-way binding or updating an array on the parent component.

Here is a concise example of the template section:

<table>
    <thead>
        <tr>
            <th> Check </th>
            <th> Title </th>
        </tr>
    </thead>
    <list-tbody v-for="element in elements" :element="element"> </list-tbody>
</table>

And here is the child component snippet:

<tbody>
    <tr>
        <td>
            <input type="checkbox">
        </td>
        <td> {{element.title}} </td>
    </tr>
</tbody>

Answer №1

Two methods for handling this situation are suggested in the comments:

  • One option is to utilize Vuex and modify the elements array from the child component.
  • The other option involves emitting an event on each selection click event to the parent, allowing the parent to update the elements array.

The preference lies with the second method, as there is no utilization of Vuex, which is perfectly acceptable.

Once the data is "linked" between the child component and the parent, a filter method can be used to display only the selected elements.

Take a look at the provided demo below or the fiddle mentioned in the comment for more details.

const listTbodyVuex = {
props: ['element'],
template: `
  <tbody>
    <tr>
        <td>
            <input type="checkbox" @click="selected">
        </td>
        <td> {{element.title}} </td>
    </tr>
</tbody>
  `,
  methods: {
  ...Vuex.mapMutations(['changeSelection']),
  selected(evt) {
      this.changeSelection({
      id: this.element.id, selected: evt.target.checked
      });
    }
  }
}

const listTbodyEvents = {
props: ['element'],
template: `
  <tbody>
    <tr>
        <td>
            <input type="checkbox" @click="selected">
        </td>
        <td> {{element.title}} </td>
    </tr>
</tbody>
  `,
  methods: {
  selected(evt) {
    console.log('clicked', evt.target.checked)
      this.$emit('selected', {
      element: this.element,
        newSelection: evt.target.checked
      })
    }
  }
}

const store = new Vuex.Store({
state: {
  elements: [
      {
      id: 0,
      title: 'first',
        selected: false
      },
      {
      id: 1,
      title: 'second',
        selected: false
      },
      {
      id: 2,
      title: 'third',
        selected: false
      }
      ]
  },
  mutations: {
  changeSelection(state, {id, selected}) {
    let element = state.elements
      .filter((element) => element.id === id)[0];
      element.selected = selected;
      Vue.set(state.elements, element.id, element);
    }
  }
})

new Vue({
el: '#app',
  store,
  data() {
  return {
    elements: [
      {
      id: 0,
      title: 'first',
        selected: false
      },
      {
      id: 1,
      title: 'second',
        selected: false
      },
      {
      id: 2,
      title: 'third',
        selected: false
      }
      ]
    }
  },
  computed: {
  ...Vuex.mapState({
    vuexElements: (state) => state.elements
    })
  },
  components: {
  listTbodyEvents,
    listTbodyVuex
  },
  methods: {
  updateElement(data) {
    let element = this.elements
      .filter((element) => element.id === data.element.id)[0];
      element.selected = data.newSelection;
    },
    filterSelected(data) {
    return data.filter((item) => item.selected);
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.0/vuex.js"></script>
<div id="app">
<h1>Example with vuex</h1>
<table>
    <thead>
        <tr>
            <th> Check </th>
            <th> Title </th>
        </tr>
    </thead>
    <list-tbody-vuex v-for="element in elements" :element="element" :key="element.id"> </list-tbody-vuex>
</table>
  <pre>only selected: {{filterSelected(vuexElements)}}</pre>
  <pre>{{vuexElements}}</pre>
  
<hr/>
<h1>Example with events</h1>
<table>
    <thead>
        <tr>
            <th> Check </th>
            <th> Title </th>
        </tr>
    </thead>
    <list-tbody-events v-for="element in elements" :element="element" :key="element.id" @selected="updateElement"> </list-tbody-events>
</table>
  <pre>only selected: {{filterSelected(elements)}}</pre>
  <pre>{{elements}}</pre>
</div>

Answer №2

To maintain a clean separation of components, it's generally best practice to stick to emitting values. However, if you're determined to retrieve all data at once, there is a workaround you can use.

In your child component, add a data attribute that your checkbox utilizes with the v-model directive. Let's say you name it checkbox_value. Then, in your parent component method, you could do something like this:

var checkbox_values = [];
this.$children.forEach(function(child) {
    // You can include a check for the child type here if needed
    checkbox_values.push(child.$data.checkbox_value);
});

While I don't recommend this approach, ultimately the decision is yours to make.

Please note: The code above will only return values. If necessary, you could modify it to push object key/value pairs instead!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Iterate through the entire array without including a specific item

I am struggling with looping through an array of items and applying some code to each item while excluding one specific item (the clicked-on item). I have experimented with using splice, but that method ends up removing the array item completely, whereas I ...

What is the best way to ensure that child elements within a container div are centered when scrolling left and right?

When attempting to handle the 'scroll' event, I noticed that the callback function only records the position of the div as the last position. I am looking for a way to determine if the div is in the center, which is my target. const slide = ...

Trouble parsing JSON in Classic ASP

After receiving a JSON Response from a remote server, everything looks good. I discovered an helpful script for parsing the JSON data and extracting the necessary values. When attempting to pass the variable into JSON.parse(), I encountered an error which ...

What is the best way to utilize props and mounted() in NuxtJS together?

I'm a beginner with NuxtJS and I'm looking to implement window.addEventListener on a specific component within my page. However, I also need to ensure that the event is removed when the page changes. In React, I would typically approach this as ...

Something went wrong with the API: an error occurred where headers were sent to the client before they could be set

Recently, I've encountered an issue where users are facing errors during registration or login. The error message pops up occasionally and here is a screenshot of it: https://i.sstatic.net/zum1u.png Below is the code snippet that I'm using: htt ...

"Sending a POST request from the smartphone application client developed using the Meteor

I'm currently working on a simple mobile app with Meteor that aims to send user location data to a geospatial database or server. However, I'm facing some challenges and uncertainties about the feasibility of this task using Meteor. The issue ari ...

The deep reactivity feature in Vue3 is functioning well, however, an error is being

I am currently using the composition API to fetch data from Firestore. While the render view is working fine, I am encountering some errors in the console and facing issues with Vue Router functionality. This might be due to deep reactivity in Vue. Here is ...

jQuery when - anticipate the fulfillment of multiple success/done callbacks

When using $.when to determine when an array of ajax promises are finished, I have noticed that although the ajax calls themselves are completed when $.when fires, their callbacks and done functions are not. How can I make sure to wait for the callbacks to ...

Conceal elements with a single click of a button

How can I use jQuery to hide all li elements with an aria-label containing the word COMPANY when the Search from documents button is clicked? Here is the HTML code: <ul class="ui-autocomplete ui-front ui-menu ui-widget ui-widget-content" id="ui-id-1" t ...

Permit the use of the "&" character in mailto href links

When including an email mailto href link and using a & character in the subject, it can cause issues with code rendering. For example, if the subject is "Oil & Gas," only "Oil" may show up. In most cases, you could simply replace the & with th ...

Issues with Gulp and Browser Sync integration

Encountering errors while running Gulp with Browser Sync in Chrome: NonESPMessageInterface --- nonEspMessageInterface.js:8 TypeError: Cannot read property 'insertBefore' of null --- angular.js:13708 Checklist message was invalid, from origin # ...

Implementing Ajax functionality in MVC 3 to return a partial view

I wanted to express my gratitude for this invaluable site that has taught me so much. Currently, I am working on an MVC3 component where I need to populate a selectlist and upon user selection, load a partial view with the relevant data displayed. Everythi ...

What steps can I take to troubleshoot the inconsistent values in my array of objects?

I am just starting out with Vue.js v2 and this project marks my first foray into it. I am baffled by an issue where my values are changing despite being only 6 lines apart from each other. The discrepancy lies between lines 966 and 972. Any insights or sug ...

Incorporating Entrance Animations for Individual Elements within ngView Using AngularJS

Can each content within ngView be animated individually upon entering, rather than the entire View (div) itself? ...

Expanding list - Using individual toggles to expand and collapse multiple list items

I stumbled upon an interesting jquery script that allows for a collapsible sub menu within a list. After implementing this code: $('.menu-item-has-children').prepend('<a id="fa-menu" href="#"><i class="fa fa-plus"></i>< ...

Vue-2 Jest-24 is encountering a test error, specifically a SyntaxError due to encountering an unexpected character, '#'

Issues Encountered with Jest Testing in Vue 2 Hello everyone, I'm currently facing difficulties while trying to run tests for my Vue 2.6 application. Specifically, I am having trouble writing tests that involve the usage of the Router and TypeScript ...

The term "Ext" has not been recognized or defined

Currently, I am facing an issue while attempting to integrate a TinyMCE plugin with ExtJs. I found a helpful demo example at this link, which I followed closely. However, my implementation is failing as I am receiving an error message stating "Ext is not ...

Encountered an issue while trying to access the length property of an undefined value within an aside

I am currently utilizing ng-strap's modal, alert, and aside features. Each of them is functioning properly on their own, but when I attempt to place an alert or modal inside an aside, it throws the following error: Uncaught TypeError: Cannot read p ...

AngularJS Default Option Selection

I am encountering some difficulties with the preselection of a select-input in angularJS. The select-box is being populated by an array. <select class="form-control" ng-model="userCtrl.selected_country" ng-options="country.name for country in userCt ...

Attaching to directive parameters

I've been working on creating a draggable div with the ability to bind its location for further use. I'm aiming to have multiple draggable elements on the page. Currently, I've implemented a 'dragable' attribute directive that allo ...