Search code examples
phplaravel-bladelaravel-8laravel-livewire

Laravel livewire adding checkbox dynamically


so i've been learning livewire for a few days i'm trying to make a checkbox added dynamically to livewire component. i already can adding the new checkbox each time i click the plus button but the problem is occured when i'm trying to click the added checkbox like on the screenshot when i try to click the 3rd checkbox, its being clicked for 1 second but then the clicked move to checkbox 1 and when i click again the 2nd checkbox is clicked after the 3rd click then the 3rd checkbox clicked it will happen to all the added checkbox

Here is the form screenshot

here is my code

addTodo.blade.php

<div x-data="{ modalOpen : false }" x-cloak >
    <div class="group text-center cursor-pointer fixed bottom-0 right-0 mb-4 mr-4 flex items-center content-center overflow-y-auto">
        <div class="group-hover:opacity-100 transition-all ease-in-out duration-300 opacity-0 p-2 mr-3 bg-white rounded text-sm">Add New Todo</div>
        <button @click="modalOpen = true" class="m-auto w-12 h-12 bg-blue-500 rounded-full shadow-lg text-lg text-white text-center">
            <svg class="mx-auto"  width="32px" height="32px" viewBox="0 0 16 16" class="bi bi-plus" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
                <path fill-rule="evenodd" d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
            </svg>
        </button>
    </div>

    <div x-show.immediate.transition.opacity="modalOpen"  class="modal--wrapper bg-black flex items-center content-center bg-opacity-50 fixed top-0 left-0 w-full h-full">

        <div  @click.away="modalOpen = false" class="modal w-1/2 shadow-lg relative bg-white rounded mx-auto ">
            <div class="modal__header flex items-center py-4 bg-blue-500 text-white px-8 rounded-tr rounded-tl">
                <span>Add new Todo</span>
                <div @click="modalOpen = false" class=" ml-auto text-white text-3xl cursor-pointer">
                    &times;
                </div>
            </div>
            <form wire:submit.prevent="addtodo">
                <div class="modal__body mt-8 px-8">
                    <div class="flex flex-col">
                        <input type="text" wire:model="title" placeholder="Todo name" class="border-2 outline-none focus:ring-blue-500 focus:border-blue-500 flex-1 block w-full rounded px-4 py-2 sm:text-sm border-gray-300" />
                    @error('title')
                        <span class="text-sm text-red-500 mt-1">{{$message}}</span>
                    @enderror
                    </div>
                    <div class="flex flex-col mt-3">
                        <textarea wire:model="description" placeholder="Todo description" class="border-2 outline-none focus:ring-blue-500 focus:border-blue-500 flex-1 block w-full rounded px-4 py-2 sm:text-sm border-gray-300"></textarea>
                    </div>

                    <div class="flex flex-col">
                        <div class="mt-3 flex items-center ">
                            <input type="text" wire:model="task.0" class="border-2 flex-1 outline-none focus:ring-blue-500 focus:border-blue-500  rounded px-4 py-2 sm:text-sm border-gray-300" placeholder="Task description" />
                            <div class="flex items-start ml-3">
                                <div class="flex items-center h-5">

                                        <label  class="text-sm ml-1 font-medium  cursor-pointer text-gray-700">
                                            <input
                                            wire:key="0"
                                            wire:model="is_done.0"
                                            id="isdone0"
                                            type="checkbox"
                                            class="focus:ring-blue-500 h-4 w-4  cursor-pointer text-blue-600 border-gray-300 rounded">
                                            Is done
                                        </label>
                                </div>
                            </div>
                            <button type="button" wire:click.prevent="add_task({{$add_index}})" class=" ml-3 focus:ring-blue-900 rounded  bg-blue-500 text-white hover:bg-blue-600">
                                <svg class="mx-auto"  width="24px" height="24px" viewBox="0 0 16 16" class="bi bi-plus" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
                                    <path fill-rule="evenodd" d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
                                </svg>
                            </button>
                        </div>
                        @error('task.0')
                            <span class="text-sm text-red-500 mt-1">{{$message}}</span>
                        @enderror
                    </div>


                    @foreach($task_input as $key => $task)
                        <div class="mt-3 flex items-center ">
                            <input type="text" wire:model="task.{{$task}}" class="border-2 flex-1 outline-none focus:ring-blue-500 focus:border-blue-500  rounded px-4 py-2 sm:text-sm border-gray-300" placeholder="Task description" />
                            <div class="flex items-start ml-3">
                                <div class="flex items-center h-5">

                                    <label
                                        wire:key="{{$task}}"
                                        class="ml-1 text-sm font-medium text-gray-700">
                                            <input
                                            wire:key="{{$task}}"
                                            wire:model="is_done.{{$task}}"
                                            id="isdone{{$task}}"
                                            type="checkbox"
                                            class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded">
                                            Is done
                                    </label>
                                </div>
                            </div>
                            <button type="button" wire:click.prevent="remove_task({{$key}})" class="ml-3 text-red-500 cursor-pointer">
                                <svg width="24px" height="24px" viewBox="0 0 16 16" class="bi bi-trash" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
                                    <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
                                    <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4L4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
                                </svg>
                            </button>
                        </div>
                        <div class="flex flex-col">
                            @error('task.*')
                                <span class="text-sm text-red-500 mt-1">{{$message}}</span>
                            @enderror
                        </div>
                    @endforeach
                </div>
                <div class="modal__footer mt-5 pt-4 pb-8 px-8">
                    <button type="submit" class="bg-blue-500 text-white px-3 py-2 rounded hover:bg-blue-600">Add Todo</button>
                </div>
            </form>
        </div>
    </div>
</div>

addTodo.php

<?php

namespace App\Http\Livewire\Todo;

use App\Models\Todo;
use App\Models\TodoItem;
use Livewire\Component;

class Addtodo extends Component
{
    public $title, $description;
    public $task, $is_done;
    public $task_input = [];
    public $add_index = 0;

    protected $rules = [
        'title' => 'required',
        'description' => 'nullable',
        'task.0' => 'required',
        'is_done.0' => 'nullable',
        'task.*' => 'required',
        'is_done.*' => 'nullable'
    ];

    protected $messages = [
        'task.0.required' => 'The task description field is required',
        'task.*' => 'The task description field is required',
    ];

    public function remove_task($i)
    {
        unset($this->task_input[$i]);
    }
    public function add_task($add_index)
    {
        $add_index = $add_index + 1;
        $this->add_index = $add_index;
        array_push($this->task_input, $add_index);
    }
    public function render()
    {
        return view('livewire.todo.addtodo');
    }
    public function addtodo()
    {
        $this->validate();
        $todo = new Todo();
        $todo->title = $this->title;
        $todo->description = ($this->description == null) ? "" : $this->description;
        $todo->creator = 1;
        $result = $todo->save();

        foreach ($this->task as $key => $task) {
            $todo_item  = new TodoItem();
            $todo_item->description = $task;
            $todo_item->is_done = ($this->is_done == null) ? false : $this->is_done[$key];
            $todo_item->todo_id = $todo->id;
            $todo_item->save();
        }

        $this->reset_fields();
        $this->emit('todoAdded');
    }

    public function reset_fields()
    {
        $this->title = "";
        $this->description = "";
        $this->task = [];
        $this->is_done = [];
        $this->task_input = [];
        $this->add_index = 0;
    }
}


Solution

  • so this happen because i haven't set the initial value of the checkbox

    i achieve the solutions simply by changing my code like this

     public function add_task($add_index)
        {
            $add_index = $add_index + 1;
            $this->add_index = $add_index;
            $this->is_done[$add_index] = false;
            array_push($this->task_input, $add_index);      
        }