In this lesson, we will add the functionality to edit and update ToDo items within your Laravel application. You will learn how to create an editing interface, handle user inputs, and update the stored data seamlessly. Here's a quick overview of the essential code snippets and their roles in this functionality:
Let's start by the view that lists all ToDo items and provides an edit button for each item:
<!-- app/resources/views/todos/index.blade.php -->
@extends('layouts.app')
@section('content')
<h1>ToDo List</h1>
<ul>
@foreach($todos as $todo)
<li>{{ $todo->title }} - {{ $todo->description }}
<a href="/todos/{{ $todo->id }}/edit">Edit</a>
<form action="/todos/{{ $todo->id }}" method="post" style="display: inline;">
@csrf
@method('DELETE')
<button type="submit">Delete</button>
</form>
</li>
@endforeach
</ul>
<form action="/todos" method="post">
@csrf
<input type="text" name="title" placeholder="Title" required>
<input type="text" name="description" placeholder="Description">
<button type="submit">Add ToDo</button>
</form>
@endsection
In the view we have an unordered list that displays all ToDo items. Each item has an "Edit" link that directs users to the edit form for that specific item. The form also includes a "Delete" button that allows users to remove the item from the list.
Wondering what users will see when they click the "Edit" link? Let's take a look at the controller method that handles the edit request:
// app/app/Http/Controllers/TodoController.php
class TodoController
{
...
public function edit($id)
{
$todo = $this->todoService->findOne($id);
return view('todos.edit', ['title' => 'Edit Todo', 'todo' => $todo]);
}
}
This method retrieves the ToDo item with the specified ID and passes it to the edit view. The view will display the item's current details and provide a form for users to update the information. Let's take a look at the edit view:
<!-- app/resources/views/todos/edit.blade.php -->
@extends('layouts.app')
@section('content')
<h1>Edit ToDo</h1>
<form action="/todos/{{ $todo->id }}" method="post">
@csrf
@method('PATCH')
<input type="text" name="title" value="{{ $todo->title }}" required>
<input type="text" name="description" value="{{ $todo->description }}">
<button type="submit">Update ToDo</button>
</form>
@endsection
The edit view displays the current title and description of the ToDo item in input fields. Users can modify these fields and submit the form to update the item. The form uses the PATCH method to send the update request to the server.
Now, let's take a look at the controller method that handles the update request:
// app/app/Http/Controllers/TodoController.php
<?php
namespace App\Http\Controllers;
use App\Services\TodoService;
class TodoController extends Controller
{
protected $todoService;
public function __construct(TodoService $todoService)
{
$this->todoService = $todoService;
}
public function index()
{
$todos = $this->todoService->findAll();
return view('todos.index', ['title' => 'ToDo List', 'todos' => $todos]);
}
public function show($id)
{
$todo = $this->todoService->findOne($id);
return view('todos.show', ['title' => 'Todo Details', 'todo' => $todo]);
}
public function store(Request $request)
{
$request->validate([
'title' => 'required|string|max:255',
'description' => 'nullable|string|max:255',
]);
$this->todoService->create($request->title, $request->description);
return redirect('/todos');
}
public function edit($id)
{
$todo = $this->todoService->findOne($id);
return view('todos.edit', ['title' => 'Edit Todo', 'todo' => $todo]);
}
public function update(Request $request, $id)
{
$request->validate([
'title' => 'required|string|max:255',
'description' => 'nullable|string|max:255',
]);
$this->todoService->update($id, $request->title, $request->description);
return redirect('/todos');
}
public function destroy($id)
{
$this->todoService->delete($id);
return redirect('/todos');
}
}
This is the same controller we've been working with, but we've added a new method called update. This method handles the update request by validating the user input, calling the update method on the TodoService, and redirecting the user back to the ToDo list view.
Finally, let's take a look at the TodoService class, which contains the update method:
// app/app/Services/TodoService.php
<?php
namespace App\Services;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
class TodoService
{
protected $filePath;
public function __construct()
{
$this->filePath = storage_path('app/todos.json');
}
public function findAll()
{
if (File::exists($this->filePath)) {
$todos = json_decode(File::get($this->filePath), false);
} else {
$todos = [];
}
return $todos;
}
public function findOne($id)
{
$todos = $this->findAll();
return collect($todos)->firstWhere('id', $id);
}
public function create($title, $description = null)
{
$todos = $this->findAll();
// Generate a random UUID for each new ToDo item
$newTodo = (object)[
'id' => (string) Str::uuid(),
'title' => $title,
'description' => $description
];
$todos[] = $newTodo;
File::put($this->filePath, json_encode($todos, JSON_PRETTY_PRINT));
return $newTodo;
}
public function update($id, $title, $description)
{
$todos = $this->findAll();
foreach ($todos as $todo) {
if ($todo->id == $id) {
$todo->title = $title;
$todo->description = $description;
}
}
File::put($this->filePath, json_encode($todos, JSON_PRETTY_PRINT));
}
public function delete($id)
{
$todos = $this->findAll();
$todos = array_filter($todos, function($todo) use ($id) {
return $todo->id != $id;
});
File::put($this->filePath, json_encode(array_values($todos), JSON_PRETTY_PRINT));
}
}
The update method in the TodoService class iterates over all ToDo items, finds the item with the specified ID, and updates its title and description. The updated list of ToDo items is then saved back to the JSON file.
Finally, let's see what are the routes that we need to add to the web.php file:
// app/routes/web.php
<?php
use App\Http\Controllers\TodoController;
Route::get('/todos', [TodoController::class, 'index']);
Route::post('/todos', [TodoController::class, 'store']);
Route::delete('/todos/{id}', [TodoController::class, 'destroy']);
Route::get('/todos/{id}/edit', [TodoController::class, 'edit']);
Route::patch('/todos/{id}', [TodoController::class, 'update']);
As you see, we've added two new routes: one for handling the edit request to display the edit form and another for handling the update request to update the ToDo item using the PATCH method.
Notice, that the first one uses GET method since it is only responsible for showing the form, which is necessary for providing new values for the ToDo item. The second one uses PATCH method, since it is responsible for updating the ToDo item based on the provided values.
That's it! You've successfully implemented the functionality to edit and update ToDo items in your Laravel application. Users can now modify the details of existing tasks, ensuring that their ToDo list remains accurate and up-to-date.