Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Mikejs's avatar

Cannot retrieve value from database on page reload/refresh

I have a tickbox to mark tasks compleate, it also updates the tasks database is_complete field ticked = 1 unticked = 0 this is all working just fine, the problem I have is if I refresh or reload the page the UI is not showing the tasks as complete, the database still shows them as is_complete = 1

This is my js

                    const todoIsDoneCheckbox = document.getElementsByName("todo-checkbox");

                    for (let i = 0; i < todoIsDoneCheckbox.length; i++) {
                        const checkbox = todoIsDoneCheckbox[i];
                        const todoListItem = checkbox.parentNode;
                        const taskId = todoListItem.getAttribute("data-task-id");

                        const statusArray = todoListItem.getAttribute("data-status").split(",");
                        const isComplete = statusArray.indexOf("done") >= 0;

                        checkbox.checked = isComplete;
                        todoListItem.setAttribute("data-complete", isComplete);

                        if (isComplete) {
                            todoListItem.classList.add("completed");
                        }

                        checkbox.addEventListener("click", function (e) {
                            const isChecked = checkbox.checked;
                            const isComplete = isChecked ? 1 : 0;

                            // Send an AJAX request to update the task completion status
                            updateTaskCompletionStatus(taskId, isComplete)
                                .then(() => {
                                    // Update the UI based on the task completion status
                                    if (isChecked) {
                                        todoListItem.classList.add("completed");
                                        statusArray.push("done");
                                    } else {
                                        todoListItem.classList.remove("completed");
                                        const index = statusArray.indexOf("done");
                                        if (index !== -1) {
                                            statusArray.splice(index, 1);
                                        }
                                    }
                                    todoListItem.setAttribute(
                                        "data-status",
                                        statusArray.join(",")
                                    );
                                    todoListItem.setAttribute("data-complete", isComplete);
                                })
                                .catch((error) => {
                                    console.error(
                                        "Error updating task completion status:",
                                        error
                                    );
                                });
                        });
                    }

                    function updateTaskCompletionStatus(taskId, isComplete) {
                        // Get the CSRF token from the page header
                        const csrfToken = document
                            .querySelector('meta[name="csrf-token"]')
                            .getAttribute("content");

                        // Send an AJAX request to update the task completion status
                        return fetch(`/tasks/${taskId}/update-completion`, {
                            method: "PUT",
                            headers: {
                                "Content-Type": "application/json",
                                "X-CSRF-TOKEN": csrfToken,
                            },
                            body: JSON.stringify({ is_complete: isComplete }),
                        }).then((response) => response.json());
                    }

This is what I have on my form

  @if ($tasks->count() > 0)
                                @php
                                    $hasVisibleTasks = false;
                                @endphp

                                @foreach ($tasks as $task)
                                    @php
                                        $task = $task->fresh(); // Refresh the task instance from the database
                                    @endphp
                                    @if ($task->is_deleted === 0)
                                        @php
                                            $hasVisibleTasks = true;
                                            $statusArray = [];
                                            if ($task->is_completed) {
                                                $statusArray[] = 'done';
                                            }
                                            if ($task->is_stared) {
                                                $statusArray[] = 'stared';
                                            }
                                            $statusArray = array_merge($statusArray, explode(',', $task->tags));
                                            $status = implode(',', $statusArray);
                                        @endphp

in my AppsController I have

  public function updateCompletionStatus(Request $request, Task $task)
{
    $isComplete = $request->input('is_complete', false);

    // Update the task's completion status in the database
    $task->is_completed = $isComplete;
    $task->save();

    // Return a JSON response indicating the success status
    return response()->json(['success' => true]);
}

I was trying to get the $tasks to update to their current state using @php $task = $task->fresh(); // Refresh the task instance from the database @endphp

but it doesn't seem to be working

0 likes
6 replies
Snapey's avatar

why is your code so complicated?

Mikejs's avatar

@Snapey Its a template I purchased, I am trying to modify so it's not just visual changes, make it usable this is the original js code for app-todo, I have tried using chatGPT to get it to work, driving me nuts!

This is the template, https://dashcode.codeshaper.net

        const todoFilters = document.querySelectorAll(".todo-categories li");
        const todoListItems = document.querySelectorAll(".todo-list li");
        const todoDeleteButtons = document.querySelectorAll(".delete-button");
        const todoNoResult = document.getElementById("no-result");

        const todoSearch = document.querySelector("#todo-search");
        const todoSidebar = document.querySelector(".todo-sidebar");
        const todoSidebarMenu = document.querySelector(".open-sidebar");
        const todooverlay = document.querySelector(".todo-todooverlay");

        if (todoNoResult) {
          todoNoResult.style.display = "none";
        }
        // mobile sidebar
        if (window.innerWidth <= 1024) {
          todoSidebar?.classList.add("enter-lg");
        }
        todoSidebarMenu?.addEventListener("click", function () {
          todoSidebar?.classList.toggle("active");
          todooverlay?.classList.toggle("active");
        });
        // todooverlay for mobile
        todooverlay?.addEventListener("click", function () {
          todoSidebar?.classList.toggle("active");
          todooverlay.classList.toggle("active");
        });

        window.addEventListener("resize", function () {
          if (window.innerWidth <= 1024) {
            todoSidebar?.classList.add("enter-lg");
          } else {
            todoSidebar?.classList.remove("enter-lg");
          }
        });

        // todo search
        todoSearch?.addEventListener("keyup", function () {
          const searchText = todoSearch.value.trim().toLowerCase();
          let visibleItemCount = 0;
          for (let i = 0; i < todoListItems.length; i++) {
            const todoListItemText = todoListItems[i].textContent.trim().toLowerCase();
            if (searchText === "" || todoListItemText.indexOf(searchText) >= 0) {
              todoListItems[i].style.display = "";
              visibleItemCount++;
            } else {
              todoListItems[i].style.display = "none";
            }
          }
          if (visibleItemCount === 0) {
            todoNoResult.style.display = "block";
          } else {
            todoNoResult.style.display = "none";
          }
        });

        for (let i = 0; i < todoFilters.length; i++) {
          todoFilters[i].addEventListener("click", function () {
            // check sidebar for mobile
            if (todoSidebar.classList.contains("active")) {
              todoSidebar.classList.remove("active");
              todooverlay.classList.remove("active");
            }
            // Remove the active class from all filters
            for (let j = 0; j < todoFilters.length; j++) {
              todoFilters[j].classList.remove("active");
            }
            // Add the active class to the clicked filter
            todoFilters[i].classList.add("active");
            const statusFilter = todoFilters[i].getAttribute("data-status");
            for (let j = 0; j < todoListItems.length; j++) {
              const todoListItemStatus = todoListItems[j].getAttribute("data-status");
              if (
                todoListItemStatus &&
                (statusFilter === "all" ||
                  todoListItemStatus.indexOf(statusFilter) >= 0)
              ) {
                todoListItems[j].style.display = "";
              } else {
                todoListItems[j].style.display = "none";
              }
            }
          });
        }

        // Add event listener to the star icons
        const todoStarIcons = document.querySelectorAll(".todo-list li .todo-fav");
        for (let i = 0; i < todoStarIcons.length; i++) {
          todoStarIcons[i].addEventListener("click", function (e) {
            const todoListItem = todoStarIcons[i].parentNode;
            const statusArray = todoListItem.getAttribute("data-status").split(",");
            const staredIndex = statusArray.indexOf("stared");
            if (staredIndex >= 0) {
              statusArray.splice(staredIndex, 1);
            } else {
              statusArray.push("stared");
            }
            todoListItem.setAttribute("data-status", statusArray.join(","));
            todoListItem.setAttribute(
              "data-stared",
              statusArray.indexOf("stared") >= 0
            );
            const activeFilter = document.querySelector(".todo-categories li.active");
            const statusFilter = activeFilter.getAttribute("data-status");
            if (
              statusFilter !== "all" &&
              todoListItem.getAttribute("data-status").indexOf(statusFilter) === -1
            ) {
              todoListItem.style.display = "none";
            } else {
              todoListItem.style.display = "";
            }
            e.stopPropagation();
          });
        }

        // delete todo
        for (let i = 0; i < todoDeleteButtons.length; i++) {
          todoDeleteButtons[i].addEventListener("click", function (e) {
            const parentListItem = todoDeleteButtons[i].closest("li");
            parentListItem.remove();
            e.stopPropagation();
          });
        }

        //  Add event listener to the checkbox
        const todoIsDoneCheckbox = document.getElementsByName("todo-checkbox");

        for (let i = 0; i < todoIsDoneCheckbox.length; i++) {
          const checkbox = todoIsDoneCheckbox[i];
          const todoListItem = checkbox.parentNode;

          const statusArray = todoListItem.getAttribute("data-status").split(",");
          const isComplete = statusArray.indexOf("done") >= 0;

          checkbox.checked = isComplete;
          todoListItem.setAttribute("data-complete", isComplete);

          if (isComplete) {
            todoListItem.classList.add("completed");
          }

          checkbox.addEventListener("click", function (e) {
            const staredIndex = statusArray.indexOf("done");
            const isChecked = checkbox.checked;

            if (staredIndex >= 0) {
              statusArray.splice(staredIndex, 1);
              checkbox.checked = false;
            } else {
              statusArray.push("done");
              checkbox.checked = true;
            }

            todoListItem.setAttribute("data-status", statusArray.join(","));
            todoListItem.setAttribute(
              "data-complete",
              statusArray.indexOf("done") >= 0
            );

            if (isChecked) {
              todoListItem.classList.add("completed");
            } else {
              todoListItem.classList.remove("completed");
            }

            const activeFilter = document.querySelector(".todo-categories li.active");
            const statusFilter = activeFilter.getAttribute("data-status");

            if (
              statusFilter !== "all" &&
              todoListItem.getAttribute("data-status").indexOf(statusFilter) === -1
            ) {
              todoListItem.style.display = "none";
            } else {
              todoListItem.style.display = "";
            }
          });
        }
Webdevashish's avatar

@mikejs Javascript looks fine. you need to put your checkbox in foreach loop

@foreach ($tasks as $task)
<div>
<input type="checkbox" value="1" name="is_completed" {{ $task->is_completed ? 'checked' : '' }} />
<p>{{ $task->content }}</p>
</div>
@endforeach
Mikejs's avatar

This is my html

    <div class="flex md:space-x-5 app_height overflow-hidden relative rtl:space-x-reverse">
        <div class="todo-sidebar ">
            <div class="h-full card">
                <div class="card-body py-6 h-full flex flex-col">
                    <div class="flex-1 h-full px-6">
                        <button class="btn inline-flex justify-center btn-dark w-full" data-bs-toggle="modal"
                            data-bs-target="#newTodoModal">
                            <span class="flex items-center">
                                <iconify-icon class="text-xl ltr:mr-2 rtl:ml-2" icon="ph:plus-bold"></iconify-icon>
                                <span>Add Task</span>
                            </span>
                        </button>
                    </div>
                    <div class="h-full px-6 " data-simplebar="data-simplebar">
                        <ul class="todo-categories list mt-6">
                            <x-todo.topfilter />
                        </ul>
                        <div class="block py-4 text-slate-800 dark:text-slate-400 font-semibold text-xs uppercase">
                            Tags
                        </div>
                        <ul class="todo-categories list">
                            <x-todo.bottomfilter />
                        </ul>
                    </div>
                </div>
            </div>
        </div>
        <div class="todo-overlay"></div>
        <div class="flex-1 md:w-[calc(100%-320px)]">
            <div class="h-full card">
                <div class="p-0  h-full relative card-body">
                    <x-todo.header />
                    <div class="h-full all-todos overflow-x-hidden" data-simplebar="data-simplebar">
                        <ul class="divide-y divide-slate-100 dark:divide-slate-700 -mb-6 h-full todo-list">
                            @foreach ($tasks as $task)
                                <li data-status="team" data-stared="{{ $task->is_starred }}"
                                    data-complete="{{ $task->is_completed }}"
                                    class="flex items-center px-6 space-x-4 py-6 hover:-translate-y-1 hover:shadow-todo transition-all duration-200 rtl:space-x-reverse">
                                    <input type="checkbox" class="table-checkbox" name="todo-checkbox">
                                    <div class="todo-fav">
                                        <iconify-icon icon="heroicons:star" class="text-xl leading-[1] relative ">
                                        </iconify-icon>
                                    </div>
                                    <span
                                        class="flex-1 text-sm text-slate-600 dark:text-slate-300 truncate bar-active transition-all duration-150">
                                        {{ $task->todo_title }}
                                    </span>
                                    <div class="flex">
                                        <span
                                            class="flex-none space-x-2 text-base text-secondary-500 flex rtl:space-x-reverse">
                                            <div
                                                class="flex justify-start -space-x-1.5 min-w-[60px] rtl:space-x-reverse">
                                                {{-- @foreach ($task->assignedUsers as $user)
                                                    <div
                                                        class="h-6 w-6 rounded-full ring-1 ring-secondary-500 img-active transition-all duration-150">
                                                        <img src="{{ $user->avatar }}" alt="{{ $user->name }}"
                                                            class="w-full h-full rounded-full">
                                                    </div>
                                                @endforeach --}}
                                            </div>
                                            <div>
                                                <span
                                                    class="bg-opacity-20 capitalize font-normal text-xs leading-4 px-[10px] py-[2px] rounded-full inline-block bg-danger-500 text-danger-500">
                                                    team
                                                </span>
                                            </div>
                                            <button type="button" class="text-slate-400" data-bs-toggle="modal"
                                                data-bs-target="#editTodoModal">
                                                <iconify-icon icon="heroicons-outline:pencil-alt"></iconify-icon>
                                            </button>
                                            <button type="button"
                                                class="transition duration-150 hover:text-danger-500 text-slate-400 delete-button">
                                                <iconify-icon icon="heroicons-outline:trash"></iconify-icon>
                                            </button>
                                        </span>
                                    </div>
                                </li>
                            @endforeach

                            <x-todo.no-result />
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade fixed top-0 left-0 hidden w-full h-full outline-none overflow-x-hidden overflow-y-auto"
        id="newTodoModal" tabindex="-1" aria-labelledby="newTodoModalLabel" aria-hidden="true">
        <div class="modal-dialog relative w-auto pointer-events-none">
            <div
                class="modal-content border-none shadow-lg relative flex flex-col lg:w-[576px] w-full pointer-events-auto bg-white bg-clip-padding
                                            rounded-md outline-none text-current">
                <div class="relative bg-white rounded-lg shadow dark:bg-slate-700">
                    <!-- Modal header -->
                    <div
                        class="flex items-center justify-between p-5 border-b rounded-t dark:border-slate-600 bg-black-500">
                        <h3 class="text-base font-medium text-white dark:text-white capitalize">
                            Add Task
                        </h3>
                        <button type="button"
                            class="text-slate-400 bg-transparent hover:text-slate-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center
                                                        dark:hover:bg-slate-600 dark:hover:text-white"
                            data-bs-dismiss="modal">
                            <svg aria-hidden="true" class="w-5 h-5" fill="#ffffff" viewbox="0 0 20 20"
                                xmlns="http://www.w3.org/2000/svg">
                                <path fill-rule="evenodd"
                                    d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
                                    clip-rule="evenodd"></path>
                            </svg>
                            <span class="sr-only">Close modal</span>
                        </button>
                    </div>
                    <!-- Modal body -->
                    <div class="p-6 space-y-4">
                        <form class="flex flex-col space-y-3" action="{{ route('tasks.store') }}" method="POST">
                            @csrf
                            <div class="input-area">
                                <label for="title" class="form-label">Title</label>
                                <input id="title" type="text" class="form-control" name="todo_title"
                                    placeholder="Enter Title">
                            </div>
                            @if (auth()->user()->hasRole('admin'))
                                <div>
                                    <label for="assigned" class="form-label">Assignee</label>
                                    <select name="user_id" id="assigneds" class="form-control w-full mt-2 py-2">
                                        @foreach ($users as $user)
                                            <option value="{{ $user->id }}">{{ $user->name }}</option>
                                        @endforeach
                                    </select>
                                </div>
                            @endif
                            {{-- <div>
                                <label for="default-picker" class="form-label">Default Functionality</label>
                                <input class="form-control py-2 flatpickr flatpickr-input active"
                                    id="default-picker" name="due_date" value="" type="text"
                                    readonly="readonly">
                            </div> --}}
                            <div>
                                <label for="tags" class="form-label">Tag</label>
                                <select name="tags" id="tagss" class="form-control w-full mt-2 py-2">
                                    <option value="Low">Low</option>
                                    <option value="Medium">Medium</option>
                                    <option value="High">High</option>
                                    <option value="Update">Update</option>
                                </select>
                            </div>
                            <div class="input-area">
                                <label for="textarea" class="form-label">Description</label>
                                <textarea name="todo_body" id="textarea" rows="3" class="form-control" placeholder="Enter Description"></textarea>
                            </div>
                            <div class="flex items-center justify-end rounded-b dark:border-slate-600">
                                <button type="submit"
                                    class="btn inline-flex justify-center text-white bg-black-500">Submit</button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade fixed top-0 left-0 hidden w-full h-full outline-none overflow-x-hidden overflow-y-auto"
        id="editTodoModal" tabindex="-1" aria-labelledby="editTodoModalLabel" aria-hidden="true">
        <div class="modal-dialog relative w-auto pointer-events-none">
            <div
                class="modal-content border-none shadow-lg relative flex flex-col lg:w-[576px] w-full pointer-events-auto bg-white bg-clip-padding rounded-md outline-none text-current">
                <div class="relative bg-white rounded-lg shadow dark:bg-slate-700">
                    <!-- Modal header -->
                    <!-- Modal header -->
                    <div
                        class="flex items-center justify-between p-5 border-b rounded-t dark:border-slate-600 bg-black-500">
                        <h3 class="text-base font-medium text-white dark:text-white capitalize">
                            Edit Task
                        </h3>
                        <button type="button"
                            class="text-slate-400 bg-transparent hover:text-slate-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-slate-600 dark:hover:text-white"
                            data-bs-dismiss="modal" id="editTaskButton">
                            <svg aria-hidden="true" class="w-5 h-5" fill="#ffffff" viewbox="0 0 20 20"
                                xmlns="http://www.w3.org/2000/svg">
                                <path fill-rule="evenodd"
                                    d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
                                    clip-rule="evenodd"></path>
                            </svg>
                            <span class="sr-only">Close modal</span>
                        </button>
                    </div>
                    <!-- Modal body -->
                    <div class="p-6 space-y-4">
                        <form class="flex flex-col space-y-3" action="{{ route('tasks.update', $task->id) }}"
                            method="POST">
                            @csrf
                            @method('PUT')
                            <div class="input-area">
                                <label for="title" class="form-label">Title</label>
                                <input id="title" type="text" class="form-control" name="todo_title"
                                    value="{{ $task->todo_title }}" placeholder="Enter Title">

                            </div>
                            @if (auth()->user()->hasRole('admin'))
                                <div>
                                    <label for="assigned" class="form-label">Assignee</label>
                                    <select name="user_id" id="assigneds" class="form-control w-full mt-2 py-2">
                                        @foreach ($users as $user)
                                            <option value="{{ $user->id }}"
                                                {{ $task->user_id == $user->id ? 'selected' : '' }}>
                                                {{ $user->name }}</option>
                                        @endforeach
                                    </select>
                                </div>
                            @endif
                            <div>
                                <label for="tags" class="form-label">Tag</label>
                                <select name="tags" id="tagss" class="form-control w-full mt-2 py-2">
                                    <option value="Low" {{ $task->tags == 'Low' ? 'selected' : '' }}>Low
                                    </option>
                                    <option value="Medium" {{ $task->tags == 'Medium' ? 'selected' : '' }}>Medium
                                    </option>
                                    <option value="High" {{ $task->tags == 'High' ? 'selected' : '' }}>High
                                    </option>
                                    <option value="Update" {{ $task->tags == 'Update' ? 'selected' : '' }}>Update
                                    </option>
                                </select>
                            </div>
                            <div class="input-area">
                                <label for="textarea" class="form-label">Description</label>
                                <textarea name="todo_body" id="textarea" rows="3" class="form-control" placeholder="Enter Description">{{ $task->todo_body }}</textarea>
                            </div>
                            <div class="flex items-center justify-end rounded-b dark:border-slate-600">
                                <button type="submit"
                                    class="btn inline-flex justify-center text-white bg-black-500">Submit</button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

 @push('scripts')
    @vite(['resources/js/custom/app-todo.js'])
 @endpush
 </x-app-layout>
Webdevashish's avatar

@mikejs

You just need to set checkbox checked based in is_completed

@foreach ($tasks as $task)
<input type="checkbox" class="table-checkbox" name="todo-checkbox" {{ $task->is_completed ? 'checked' : '' }}>
@endforeach  
1 like

Please or to participate in this conversation.