Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue v-model does not work with individual index of array

I have a row of inputs: a checkbox and a dropdown button.

Then, there is another button to add a new row of inputs.

The checkbox, when checked would disable the dropdown and make it non-required.

<template>
  <div>
    <tr v-for="(item, i) of timesheet.items" :key="i">
    <div>
        <td>
            <input 
                type= "checkbox"
                v-model="checked"
                id= "{{ 'disable' + i }}" 
                v-on:click= "disable(i)"
            >
        </td>
        <td>
            <select2 
                :id="'project_id-' + i" 
                v-bind:class="{
                    'is-invalid': item.project_id.$error,
                    'is-valid':
                    item.project_id.$dirty &&
                    !item.project_id.$error,
                }"
            >
                <option value="">Select</option>
                <option v-for="(project) in projects" 
                    :selected="project.id == timesheet.project_id" 
                    :key="project.id" 
                    :value="project.id">{{ project.name }}</option>
            </select2>
        </td>
        <td>
            <button 
                type="button" 
                class="btn btn-sm btn-primary" 
                @click="itemCount++"
            >Add Row
            </button>
        </td>
    </div>
    </tr>
  </div>
</template>
<script>
    import { required, minLength } from "vuelidate/lib/validators";
    export default {
        data() {
            return {
                checked: false,
                timesheet: { items: [{ project_id: "" }] },
            }
        },
        validations() {
            if (!this.checked) {
                return{
                    itemCount: 1,
                    timesheet: {
                        items: {
                            required,
                            minLength: minLength(1),
                            $each: { project_id: { required }}
                        }
                    }
                }
            }else{
                return{
                    timesheet: {
                        items: {
                            required,
                            minLength: minLength(1),
                            $each: { project_id: {} }
                        }
                    }
                }                
            }
        },
        watch: {
            itemCount(value, oldValue) {
                if (value > oldValue) {
                    for (let i = 0; i < value - oldValue; i++) {
                        this.timesheet.items.push({
                            project_id: "",
                            checked: false,
                        })
                    }
                } else {
                    this.timesheet.items.splice(value);
                }
            }
        },
        methods: {            
            disable(index){
                const check = 
                        document.getElementById('project_id-' + index).disabled
                $('#project_id-' + index).attr('disabled', !check);
            }
        },        
    }
</script>   

The first checkbox does the work as intended but, whenever another row is added, the new one is always pre-checked and is behaving the exact opposite of the first.

So, my question is how do I fix my v-model?

like image 970
user16780927 Avatar asked Jan 22 '26 11:01

user16780927


1 Answers

There a couple of problems I see with your code.

First, the checkbox has id= "{{ 'disable' + i }}", using interpolation in attributes is not allowed, you should use :id="'disable' + i".

Second, I still don't understand where you've defined itemsCount, I'll assume its under data.

Third, you're using the same v-model for all checkboxes, which is your checked model under data. So clicking any checkbox will change checked and this change will be updated in other checkboxes as well. Which is why all your checkboxes behave in sync.

Fourth, you've defined timesheet: { items: [{ project_id: "" }] }, so item only contains project_id property. But later when you add items you use this.timesheet.items.push({ project_id: "", checked: false }), which tells me you're trying to have the checked property for each item, which you meant to use for each checkbox. Well, then you have the right idea.

What you need to do is add a checked property to items in data, and use this as v-model for your checkboxes.

  data() {
    return {
      itemCount: 1,
      timesheet: { items: [{ project_id: "", checked: false }] },
    };
  },
<input
  type="checkbox"
  v-model="item.checked"
  :id="'disable' + i"
  v-on:click="disable(i)"
/>
like image 55
Mythos Avatar answered Jan 24 '26 00:01

Mythos