Using a prop array as v-model in a Vue JS CheckBoxGroup implementation

Struggling to create a reusable CheckBoxGroup component with a prop array as v-model. I checked out the vuejs guide at https://v2.vuejs.org/v2/guide/forms.html#Checkbox which uses the v-model array in the data of the same component. However, this approach is limiting if I want to pass the v-model via props and have the ability to check some boxes from outside the component.

CheckBoxgroup.vue

<template>
  <div>
    <label v-for="day in allDays" :key="day">
      <input v-model="checkedDays" type="checkbox" :value="day" />
      <span>{{ day }}</span>
    </label>
    <div>Checked days: {{ checkedDays }}</div>
 </div>
</template>
<script lang="ts">
import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'

@Component
export default class CheckBoxGroup extends Vue {
  @Prop() checkedDays!: string[]

  @Prop() allDays!: string[]
}
</script>

Index.vue

<template>
  <div>
    <checkbox-group :checked-days="checkedDays" :all-days="allDays" />
  </div>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import CheckboxGroup from './checkBoxGroup.vue'

@Component({
  components: { CheckboxGroup },
})
export default class Index extends Vue {

  // This list would usually come from an API
  allDays = ['Monday', 'Tuesday', 'Wednesday']

  checkedDays = ['Monday']
}
</script>

The code works fine, but I am encountering the warning: [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders... Is there a way around this issue? Any suggestions would be greatly appreciated.

Answer №1

Modifying the parent state directly from the children is not allowed in Vue.js, but you can trigger an event in the child component which will be handled by the parent to update the state. Here's an example:

Vue.component('check-box-group', {
  template: `
    <div>
      <label v-for="day in allDays" :key="day">
        <input 
          v-model="checkedDays" 
          :value="day" 
          @click="$emit('update-checked-days', { newCheckedDay: day })"
          type="checkbox" 
        />
        <span>{{ day }}</span>
      </label>
      <div>Checked days: {{ checkedDays }}</div>
    </div>
  `,
  props: {
    checkedDays: {
      type: Array,
      default: () => ([])
    },
    allDays: {
      type: Array,
      default: () => ([])
    },
  }
})

new Vue({
  el: "#app",
  data() {
    return {
      allDays: ['Monday', 'Tuesday', 'Wednesday'],
      checkedDays: ['Monday']
    }
  },
  methods: {
    HandleUpdateCheckedDays({newCheckedDay}) {
      const indexOfCheckedDay = this.checkedDays.findIndex(checkedDay => checkedDay === newCheckedDay)

      if (indexOfCheckedDay === -1) { // if not exists then add to checkedDays
        this.checkedDays.push(newCheckedDay)
      } else {
        this.checkedDays = this.checkedDays.filter((_, i) => i !== indexOfCheckedDay)
      }
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>

<div id="app">
  <check-box-group 
    :checked-days="checkedDays" 
    :all-days="allDays" 
    @update-checked-days="HandleUpdateCheckedDays"
  />
</div>

note: keep in mind that TS class composition is no longer supported.

Answer №2

Appreciate the input, I was able to successfully resolve it using v-model too, but it felt a bit makeshift and less versatile when dealing with externally injected data Models. Therefore, I've decided to adopt your approach.

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

What could be causing my controller method in TypeScript to throw an error message unexpectedly?

Hey there. I'm diving into TypeScript and currently working on converting an Express backend to TS. Everything was smooth sailing until I encountered some unexpected issues. Specifically, the lines const hasVoted = poll.votedBy.some((voter): boolean = ...

Utilize JavaScript to iterate through two sets of numbers

I am currently working on a project that requires me to iterate through two continuous number ranges: 1 to 5 and 10 to 15. This is the code I'm using: var X = []; for (i = 1; i < 6; i++) { X.push(i); } for (i = 10; i < 16; i++) { X.push(i ...

Trigger the function when the keyboard event is deactivated

Is there a way to continuously run the top set interval whenever I lift my finger from the space key? When I try using the key up event, it only executes that function once. I'm not sure how to implement if/else logic when adding an event listener. se ...

Can the useEffect hook prevent the page from rendering?

Is there a way to have a slight delay every time the user visits or reloads the page in order to allow for content loading? Currently, I am using a useEffect() with a setTimeout() function that sets the variable isLoading to false after 1 second. However, ...

Array containing two objects in a two-dimensional format

In the example provided, I am working with a 2D array. Link to the example: https://codesandbox.io/s/v0019po127 I am noticing different results depending on whether I use the browser console or Codesandbox's console. I have attempted using JSON.str ...

Altering the DOM directly within the componentDidMount() lifecycle method without needing to use

In ReactJS, I am facing an issue while trying to manipulate the DOM in the componentDidMount() method. The problem lies in the fact that the DOM is not fully rendered at this point, requiring me to use a setTimeout function, which I find undesirable. Upon ...

Deactivating controls while displaying the loading bar in AngularJS

I'm currently working on a web application using AngularJS. I want to incorporate a loading bar to signify long data load times from the server. To replicate heavy data loads, I am utilizing $timeout to trigger the loadbar when the operation begins a ...

Running "vue ui" with Node.js v17.2.0 - A step-by-step guide

After updating to Node.js v17.2.0, I am facing issues with running "vue ui" in my project. The error message I receive indicates a problem with node modules: at Object.readdirSync (node:fs:1390:3) at exports.readdir (/usr/local/lib/node_modules/@vu ...

Obtain offspring from a parent element using jQuery

$(document).ready(function() { $.ajax({ type: "POST", url: 'some/url', data: { 'name':'myname' }, success: function (result) { var result = ["st ...

Exploring ways to retrieve item metadata from a Stripe checkout session

When setting up a Checkout session, I dynamically create prices using the price_data and product_data properties. I include metadata for each item within the product_data.metadata property. However, after a successful payment is made, I retrieve the sessi ...

Implementing multiple filters with jQuery

Make a Selection `<select class="form-control" id="technology"> <option name="sort" value="2g" id="2g"gt;2G</option> <option name="sort" value="3g" id="3g"&g ...

What steps should I follow to set JSONP as the dataType for a request in an Angular $http service?

I have a good understanding of how to use jQuery's $.ajax: $.ajax({ url: //twitter endpoint, method:"GET", dataType:"jsonp", success:function() { //stuff } }); Is there a way to set the JSONP datatype for an angular $http service reque ...

Animate the height transition of contenteditable after a line of text is added (using shift+enter) or removed

Currently, the contenteditable attribute is being utilized on the <div> tag to enable autogrow functionality similar to a textbox. Additionally, there is an attempt to incorporate a height transition. While most aspects are functioning correctly, the ...

Endless cycle of changing border colors

I'm trying to achieve a specific effect where the border of a div changes colors in an infinite loop. However, I want this effect to be applied only to the border of the div and not the entire body background. Here is an example: http://jsfiddle.net/A ...

Challenge with uploading Minio presigned URLs

I am encountering a problem with the Minio presigned URL. While I have successfully obtained the URL and used the PUT method to insert my file into my Minio bucket, I am unable to open certain file types such as jpg, png, or pdf. This is due to Minio autom ...

Is there a way to prevent tinymce from automatically inserting <!DOCTYPE html><html><head></head><body> before all my content?

I have integrated TinyMCE as the editor for one of my database fields. The issue I am encountering is that when I input the text "abc" into the editor, it gets saved in the database surrounded by unnecessary HTML elements. This is the structure currently s ...

Hide the HTML DIV without altering the position of the current div

My goal is to conceal elements 1, 3 and 2 & 4 without changing their position. div{ width: 10%; float: left; } <div style="background-color: blue"><p>1</p></div> <div style="background-color: yellow"><p>2</ ...

Steps for Adding a class or Id to an Ext.Msg.alert box

Is there a way to customize the style of a specific Ext alert box without affecting all alert boxes? Can someone please explain how to assign a class or ID to an Ext.Msg.alert box? Ext.Msg.alert('Status', 'Changes saved successfully.' ...

Is there a way to access the v-model of the component that triggered a function in Vuetify?

In my current project, I am working on a form that requires each text-field to interact with one another. Here is an example of what I have: <template> <v-app> <v-text-field v-model="foo1" @input="updateForm"> < ...

What is the best way to set up an external site iframe that utilizes PHP as a proxy on my web server without encountering CORS issues?

I came across a tutorial on using curl in php, and here is what I have implemented so far: index.html: <!DOCTYPE html> <html> <head> </head> <body> <iframe src="fetch.php" width="800" height="500"></iframe> </ ...