@pretom can you reformat your question please?
to code indent use 3 back ticks before and after your codeblocks.
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
I build a Task Management project using laravel & vue js which is worked very nicely.But edit function can't work properly in this application.I tried a lot but failed.Even when clicked edit option this would work to same as create/add function.How can I solve this problem.I will share my code below:
resource/js/app.js
require("./bootstrap");
window.Vue = require("vue");
/ / Register our components
Vue.component("kanban-board", require("./components/KanbanBoard.vue").default);
const app = new Vue({
el: "#app"
});
resource/js/components/KanbanBoard.vue
<template>
<div class="relative p-2 flex overflow-x-auto h-full">
<!-- Columns (Statuses) -->
<div
v-for="status in statuses"
:key="status.slug"
class="mr-6 w-4/5 max-w-xs flex-shrink-0"
>
<div class="rounded-md shadow-md overflow-hidden">
<div class="p-1 flex justify-between items-baseline bg-green-500 ">
<h4 class="font-medium text-white">
{{ status.title }}
</h4>
</div>
<div class="p-2 bg-green-300">
<!-- AddTaskForm -->
<AddTaskForm
v-if="newTaskForStatus === status.id"
:status-id="status.id"
v-on:task-added="handleTaskAdded"
v-on:task-canceled="closeAddTaskForm"
/>
<!-- ./AddTaskForm -->
<!-- EditTaskForm -->
<AddTaskForm
v-if="editTaskForStatus === status.id"
:status-id="status.id"
v-on:task-edit="handleTaskEdit"
v-on:task-canceled="closeEditTaskForm"
/>
<!-- ./EditTaskForm -->
<!-- Tasks -->
<draggable
class="flex-1 overflow-hidden"
v-model="status.tasks"
v-bind="taskDragOptions"
@end="handleTaskMoved"
>
<transition-group
class="flex-1 flex flex-col h-full overflow-x-hidden overflow-y-auto rounded shadow-xs"
tag="div"
>
<div
v-for="task in status.tasks"
:key="task.id"
class="mb-3 p-4 flex flex-col bg-white rounded-md shadow transform hover:shadow-md cursor-
pointer"
>
<button
type="submit"
@click="openEditTaskForm(status.id)"
class="py-1 px-2 text-sm text-black-500 hover:underline"
>
Edit Task
</button>
<span class="block mb-2 text-xl text-gray-900">
Task-100{{ task.id }}
</span>
<span class="block mb-2 text-xl text-gray-900">
{{ task.title }}
</span>
<p class="text-gray-700">
{{ task.description }}
</p>
</div>
<!-- ./Tasks -->
</transition-group>
</draggable>
<!-- No Tasks -->
<div
v-show="!status.tasks.length && newTaskForStatus !== status.id"
class="flex-1 p-4 flex flex-col items-center justify-center"
>
<!-- <span class="text-gray-600">No tasks yet</span> -->
<button
class="mt-1 text-sm text-orange-600 hover:underline"
@click="openAddTaskForm(status.id)"
>
Add one
</button>
</div>
<!-- ./No Tasks -->
</div>
</div>
<button
type="submit"
@click="openAddTaskForm(status.id)"
class="px-12 py-1 leading-5 text-white bg-orange-600 hover:bg-orange-500 rounded"
>
Add
</button>
</div>
<!-- ./Columns -->
</div>
</template>
<script>
import draggable from "vuedraggable";
import AddTaskForm from "./AddTaskForm";
import EditTaskForm from "./EditTaskForm";
export default {
components: { draggable, AddTaskForm,EditTaskForm },
props: {
initialData: Array
},
data() {
return {
statuses: [],
newTaskForStatus: 0,
editTaskForStatus: 0
};
},
computed: {
taskDragOptions() {
return {
animation: 200,
group: "task-list",
dragClass: "status-drag"
};
}
},
mounted() {
// 'clone' the statuses so we don't alter the prop when making changes
this.statuses = JSON.parse(JSON.stringify(this.initialData));
},
methods: {
openAddTaskForm(statusId) {
this.newTaskForStatus = statusId;
},
closeAddTaskForm() {
this.newTaskForStatus = 0;
},
handleTaskAdded(newTask) {
// Find the index of the status where we should add the task
const statusIndex = this.statuses.findIndex(
status => status.id === newTask.status_id
);
// Add newly created task to our column
this.statuses[statusIndex].tasks.push(newTask);
// Reset and close the AddTaskForm
this.closeAddTaskForm();
},
handleTaskMoved(evt) {
axios.put("/tasks/sync", { columns: this.statuses }).catch(err => {
console.log(err.response);
});
},
openEditTaskForm(statusId) {
this.editTaskForStatus = statusId;
},
closeEditTaskForm() {
this.editTaskForStatus = 0;
},
handleTaskEdit(editTask) {
// Find the index of the status where we should add the task
const statusIndex = this.statuses.findIndex(
status => status.id === editTask.status_id
);
// Add newly created task to our column
this.statuses[statusIndex].tasks.push(editTask);
// Reset and close the AddTaskForm
this.closeEditTaskForm();
}
}
};
</script>
<style scoped>
.status-drag {
transition: transform 0.5s;
transition-property: all;
}
</style>
resource/js/components/AddTask.vue
<template>
<form
class="relative mb-3 flex flex-col justify-between bg-white rounded-md shadow overflow-hidden"
@submit.prevent="handleAddNewTask"
>
<div class="p-3 flex-1">
<input
class="block w-full px-2 py-1 text-lg border-b border-blue-800 rounded"
type="text"
placeholder="Enter a title"
v-model.trim="newTask.title"
/>
<textarea
class="mt-3 p-2 block w-full p-1 border text-sm rounded"
rows="2"
placeholder="Add a description"
v-model.trim="newTask.description"
></textarea>
<div v-show="errorMessage">
<span class="text-xs text-red-500">
{{ errorMessage }}
</span>
</div>
</div>
<div class="p-3 flex justify-between items-end text-sm bg-gray-100">
<button
@click="$emit('task-canceled')"
type="reset"
class="py-1 leading-5 text-gray-600 hover:text-gray-700"
>
cancel
</button>
<button
type="submit"
class="px-3 py-1 leading-5 text-white bg-orange-600 hover:bg-orange-500 rounded"
>
Add
</button>
</div>
</form>
</template>
<script>
export default {
props: {
statusId: Number
},
data() {
return {
newTask: {
title: "",
description: "",
status_id: null
},
errorMessage: ""
};
},
mounted() {
this.newTask.status_id = this.statusId;
},
methods: {
handleAddNewTask() {
// Basic validation so we don't send an empty task to the server
if (!this.newTask.title) {
this.errorMessage = "The title field is required";
return;
}
// Send new task to server
axios
.post("/tasks", this.newTask)
.then(res => {
// Tell the parent component we've added a new task and include it
this.$emit("task-added", res.data);
})
.catch(err => {
// Handle the error returned from our request
this.handleErrors(err);
});
},
handleErrors(err) {
if (err.response && err.response.status === 422) {
// We have a validation error
const errorBag = err.response.data.errors;
if (errorBag.title) {
this.errorMessage = errorBag.title[0];
} else if (errorBag.description) {
this.errorMessage = errorBag.description[0];
} else {
this.errorMessage = err.response.message;
}
} else {
// We have bigger problems
console.log(err.response);
}
}
}
};
</script>
resource/js/components/EditTask.vue
<template>
<form
class="relative mb-3 flex flex-col justify-between bg-white rounded-md shadow overflow-hidden"
@submit.prevent="handleEditTask"
>
<div class="p-3 flex-1">
<input
class="block w-full px-2 py-1 text-lg border-b border-blue-800 rounded"
type="text"
@blur="handleEditTask(task)"
v-model="editTask.title"
/>
<textarea
class="mt-3 p-2 block w-full p-1 border text-sm rounded"
rows="2"
p
@blur="handleEditTask(task)"
v-model="editTask.description"
></textarea>
<div v-show="errorMessage">
<span class="text-xs text-red-500">
{{ errorMessage }}
</span>
</div>
</div>
<div class="p-3 flex justify-between items-end text-sm bg-gray-100">
<button
@click="$emit('task-canceled')"
type="reset"
class="py-1 leading-5 text-gray-600 hover:text-gray-700"
>
cancel
</button>
<button
type="submit"
class="px-3 py-1 leading-5 text-white bg-orange-600 hover:bg-orange-500 rounded"
>
Add
</button>
</div>
</form>
</template>
<script>
export default {
props: {
statusId: Number
},
data() {
return {
editTask: {
title:task.title,
description:task.description,
status_id: null
},
errorMessage: ""
};
},
mounted() {
this.editTask.status_id = this.statusId;
},
methods: {
handleEditTask() {
// Basic validation so we don't send an empty task to the server
if (!this.editTask.title) {
this.errorMessage = "The title field is required";
return;
}
// Send edit task to server
axios
.patch("tasks/{task}", this.editTask)
.then(res => {
// Tell the parent component we've added a new task and include it
this.$emit("task-edit", res.data);
})
.catch(err => {
// Handle the error returned from our request
this.handleErrors(err);
});
},
handleErrors(err) {
if (err.response && err.response.status === 422) {
// We have a validation error
const errorBag = err.response.data.errors;
if (errorBag.title) {
this.errorMessage = errorBag.title[0];
} else if (errorBag.description) {
this.errorMessage = errorBag.description[0];
} else {
this.errorMessage = err.response.message;
}
} else {
// We have bigger problems
console.log(err.response);
}
}
}
};
</script>
app/Http/Controllers/TaskController
<?php
namespace App\Http\Controllers;
use App\Task;
use Illuminate\Http\Request;
class TaskController extends Controller
{
public function index()
{
$tasks = auth()->user()->statuses()->with('tasks')->get();
return view('tasks.index', compact('tasks'));
}
public function create()
{
//
}
public function store(Request $request)
{
$this->validate($request, [
'title' => ['required', 'string', 'max:56'],
'description' => ['nullable', 'string'],
'status_id' => ['required', 'exists:statuses,id']
]);
return $request->user()
->tasks()
->create($request->only('title', 'description', 'status_id'));
}
public function sync(Request $request)
{
$this->validate(request(), [
'title' => ['required', 'string', 'max:56'],
'description' => ['nullable', 'string'],
'columns' => ['required', 'array']
]);
foreach ($request->columns as $status) {
foreach ($status['tasks'] as $i => $task) {
$order = $i + 1;
if ($task['status_id'] !== $status['id'] || $task['order'] !== $order) {
request()->user()->tasks()
->find($task['id'])
->update(['status_id' => $status['id'], 'order' => $order],$request->only('title', 'description',
'status_id'));
}
}
}
return $request->user()->statuses()->with('tasks')->get();
}
public function show(Task $task)
{
//
}
public function edit(Request $request)
{
}
public function update(Request $request, Task $task)
{
$this->validate($request, [
'title' => ['required', 'string', 'max:56'],
'description' => ['nullable', 'string'],
'status_id' => ['required', 'exists:statuses,id']
]);
return $request->user()
->tasks()
->update($request->only('title', 'description', 'status_id'));
}
public function destroy(Task $task)
{
//
}
}
resource/views/tasks/index.blade.php
@extends('layouts.app')
@section('content')
<div class="md:mx-4 relative overflow-hidden">
<main class="h-full flex flex-col overflow-auto">
<kanban-board :initial-data="{{ $tasks }}"></kanban-board>
</main>
</div>
@endsection
web.php
Route::group(['middleware' => 'auth'], function () {
Route::get('tasks', 'TaskController@index')->name('tasks.index');
Route::post('tasks', 'TaskController@store')->name('tasks.store');
Route::put('tasks/sync', 'TaskController@sync')->name('tasks.sync');
Route::put('tasks/{task}', 'TaskController@update')->name('tasks.update');
});
Route::group(['middleware' => 'auth'], function () {
Route::post('statuses', 'StatusController@store')->name('statuses.store');
Route::put('statuses', 'StatusController@update')->name('statuses.update');
});
Please or to participate in this conversation.