Home » vue » How to have Vue dynamic button disabled based on checkbox from list

How to have Vue dynamic button disabled based on checkbox from list

Posted by: admin November 26, 2021 Leave a comment

Questions:

I’ve created a Todo app while learning Vue, so far so good. I have on issue where initially I set the tasks delete button to disabled and want to have it be enabled only if the checkbox related is checked. As of now when I click any task checkbox ALL the buttons are affected. Not sure how you would create a relation to the 2 elements.

 <template>
        <div class="mt-5 todos-list">
          <div
            v-for="todo in todos"
            :key="todo.id"
            class="flex justify-between pb-4 todos-item"
          >
            <div class="flex items-center mr-10 todos-item__checkbox">
              <input
                v-model="checkboxes"
                :value="todo.task.title"
                type="checkbox"
                class="w-4 h-4 mr-2 border-2 border-red-500 appearance-none checked:bg-red-600 checked:border-transparent"
                @change="checkBoxChecked($event)"
              />
              <label for="todo" class="text-lg font-medium todos-checkbox ">{{
                todo.task.title
              }}</label>
            </div>
            <div class="todos-item__button">
              <button
                class="rounded-lg btn btn-delete"
                :class="{ disabled: btnDisabled[index] }"
                type="button"
                :disabled="btnDisabled[index]"
                @click="deleteTask(todo.task.id)"
              >
                Delete
              </button>
            </div>
        <AddTodo @addTodo="addTask" />
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          checkboxes: [],
          btnDisabled: [],
          todos: [
            {
              task: {
                id: 1,
                title: 'Go to store',
                isComplete: false
              }
            },
            {
              task: {
                id: 2,
                title: 'Go for walk',
                isComplete: false
              }
            },
            {
              task: {
                id: 3,
                title: 'Take dog out',
                isComplete: false
              }
            }
          ]
        }
      },
  mounted() {
    const disableArr = this.todos.map((el) => true)
    this.btnDisabled.push(...disableArr)
  },
      methods: {
        addTask(title) {
          this.todos.push({
            task: {
              id: Math.ceil(Math.random() * 1000000),
              title,
              isComplete: false
            }
          })
        },
        deleteTask(id) {
          const index = this.todos.findIndex((item) => item.id === id)
          this.todos.splice(index, 1)
        },
         checkBoxChecked(event, index) {
  if (event.target.checked) {
    this.btnDisabled = this.btnDisabled.map((el, i) => index !== i)
  } else {
    this.btnDisabled = this.btnDisabled.map((el, i) => index === i)
  }
}
      }
    }
    </script>
Answers:

I think it is because you only just have one boolean state for all of your todos. Maybe it will work if you change btnDisabled data into array, so each todo will have their own disabled or not disabled state on their own.

Here are one way of what I’m trying to point out

Change btnDisabled into array

btnDisabled = this.todos.map(el => true)

Add index to v-for

v-for="(todo,index) in todos"

Pass index to @change

@change="checkBoxChecked($event,index)"

Modify checkBoxChecked Method

checkBoxChecked(event, index) {
  if (event.target.checked) {
    this.btnDisabled = this.btnDisabled.map((el,i) => index === i ? false : true)
  } else {
    this.btnDisabled = this.btnDisabled.map((el,i) => index === i ? true : false)
  }
}

bind disabled to specific index of btnDisabled

:disabled="btnDisabled[index]"

Hope this solve your issue