Laravel 9 CRUD Tutorial Example for Beginners with Todo App – Crash Course

August 7, 2022
Laravel
Laravel 9 CRUD Tutorial Example for Beginners with Todo App – Crash Course

In this comprehensive guide and tutorial in which you will learn how to do the CRUD (Create Read Update and Delete) Operation in laravel 9.

🔴 How To Execute CRUD Using Djan...
🔴 How To Execute CRUD Using Django Ajax and JSON

This is the Crash Course created keeping Beginners in mind so that they can follow along. In this tutorial, we will going to create todo app using Bootstrap 5 in laravel 9.

Let’s get started!

Table of Contents

Prerequisites:

In order to learn and install laravel 9, there are some requirements which is must to have in order to understand properly. These requirements consists of technical requirements and the knowledge requirements.

Technical/System Requirements for laravel 9:

  • You must have a minimum PHP 8.0 installed in your system for laravel 9
  • Make sure you have installed the composer to install the laravel and PHP packages
  • MYSQL for the database

And Some of the PHP extensions:

These extensions of PHP are also required to install in order to work laravel properly:

  • BCMath PHP Extension
  • Ctype PHP Extension
  • Fileinfo PHP extension
  • JSON PHP Extension
  • Mbstring PHP Extension
  • OpenSSL PHP Extension
  • PDO PHP Extension
  • Tokenizer PHP Extension
  • XML PHP Extension

Knowledge Requirements for learning laravel:

In order to learn the laravel, some you must have knowledge of :

  • PHP and its concepts (Beginner to Intermediate Level)
  • OOP Concepts
  • MYSQL Concepts

If you have good or above average knowledge of above, you are good to proceed.

What is Laravel?

Laravel is based on PHP framework which works on MVC (Model View Controller) that allow us to create web applications more seamlessly and securely. It provides also very easy to scale.

Being open-source framework, laravel not only has made the web development easy but also the community which they have build, continuously ships tons of new features and new packages on the frequent basis.

Due to those features, laravel framework is one of the most popular PHP framework.

What is MVC Architecture?

MVC Stands for Model, View and Controller.

Laravel is based on MVC Architecture which allow us to split the code in parts for better organization and keeping the code clean so that its always ready to scale for new features.

  • Model is way of querying data to and from the table using database
  • View basically contains the frontend of the application (HTML)
  • Controller is responsible for satisfying request and contains the business logic

Step 1: Install Laravel

Let’s first install the laravel in laravel_crud folder using terminal:

composer create-project --prefer-dist laravel/laravel laravel_crud 

You will see something like this in the terminal:

Laravel Installation

It means the laravel framework has been successfully downloaded and installed.

Then open up the project in your favorite editor/IDE. I am using PHPStorm IDE. You will see the following files

Laravel directory

Step 2: Update DB Credentials

Now go the .env and change the DB_DATABASE, DB_USERNAME, DB_PORT and DB_PASSWORD according to your database details.

env file for laravel 9 Tutorial for Beginners

Step 3: Migrate Database

What is Laravel Migration?

Laravel migration is one of the laravel’s popular feature which let us create, modify and delete tables and its columns.

Laravel ships some of the migration files for some tables by default which includes users, password resets, failed_jobs and personal_access_tokens and migrations tables.

Note: You can see that tables names are plural. Will explain later on why it is so when we create the modal.

And you can see them by going to database/migrations folder:

Migration files for laravel

How to migrate?

So now in order to convert that migration files to tables in the database, we run to migrate by using the following command in the terminal:

php artisan migrate

You will see the following output in the terminal:

Migrated result for laravel 9 Tutorial for Beginners

And if you open the database you will see that your database will now have 5 tables which I have mentioned above:

Database View in laravel

Step 4: Run Application

Now in order to start application, you need to type following command in the terminal:

php artisan serve

You will see in the terminal that the application will get started and will give you URL to access it.

In my case, the access url is . If you type this in browser you will see following screen:

Laravel 9 Welcome Page

If you see the above screen, it means you have ran the laravel 9. Hurray!

Make sure the next command for terminal, you do in the another terminal, and dont close this terminal otherwise you have run again using php artisan serve command.

Step 5: Create Migration for the todos table

Since we are creating the todo app, we need to create the todo table, in which we will store all todo.

We will have the following columns in todo table:

  • title
  • is_completed

Let’s create the migration file for the todo table by typing the following command:

php artisan make:migration create_todos_table

This will create a new migration file in the database/migrations folder with the name of create_todos_table.php with some date prefix which will contains some following code:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('todos', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('todos');
    }
};

The up() the function is basically the function where we create the table and as you can see that some code is already written for the todos table and you can see the id() and timestamps().

Theid() and timestamps() are columns that automatically get added when we have created the migration file. Those columns can be removed if want, but i will keep them in this case.

Now lets add the title and is_completed columns.

The final up() function will look like this:

 public function up()
    {
        Schema::create('todos', function (Blueprint $table) {
            $table->id();
            $table->longText('title');
            $table->boolean('is_completed')->default(0);
            $table->timestamps();
        });
    }

We added the title as the longText and is_completed as boolean with the default value of 0. We will consider 0 as the not completed and 1 as the completed.

Now you need to migrate again by using following command:

php artisan migrate

You will see that your todos table is migrated now.

Laravel Migration Result

Step 6: Create Model for the todos table

What is a Model in laravel?

Model in laravel is a way of querying data to and from the table within the database.

How to Create a Model?

Since we want to create model for our todos table, we will create that by using following command:

php artisan make:model Todo

This will create the Todo Model for our todos table.

Note: You can see that model name is Singular (Todo) where as the migration and the table name is Plural (todos), this is how the laravel recommends the naming scheme should be.

Now if you go to the app/Models you will see that Todo Model is now gets created.

Laravel Model Creation

Setting up the model:

If you open that up, you will see something like this:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Todo extends Model
{
    use HasFactory;
}

Now after use HasFactory; type:

protected $guarded=[];

You can see that in $guarded variable, we have added an empty array.

This means don’t allow the columns values to get changed or added which we have mentioned in the array.

But since we haven’t added any column in the array, all column values can get changed.

Step 7: Create Controller and Route

What is a Controller in laravel?

A Controller controls the behavior of the request. It accepts request coming from the route and satisfy them.

In the controller, we usually write all of our business logic. Usually, we validate the request and then fetching data from the database using model

How to Create Controller ?

In order to create controller for our Todo Model or todos table, you need to type the following command:

php artisan make:Controller TodoController --resource

You will see something like this:

Laravel Creating Controller

This will allow us to create the controller, where as --resource is to declare as the resource which create some empty functions like index, create, store, show, edit, update anddestroy to save time that we will use these functions to add our business logic to make CRUD operation.

What is a Route in laravel?

Route is a way of requesting data from end users. The route is usually tied with controller function.

In simple terms it means that if the user types this in URL execute that controller funtion which is tied to that route.

How to Create Route?

In order to create the route as the resource, go to routes/web.php file and at the end of the file write:

Route::resource('todos', \App\Http\Controllers\TodoController::class);

This will now allow us to access all the functions of the TodoController.

How to see all the Routes?

If you want to see, all the able routes you can type the following command in the terminal:

php artisan route:list

You will be able to see all the available routes for our application.

How to see all routes in laravel

You can see that we have a bunch of route endpoints, and we will use a few of them only for now in this application.

  • todos.index GET method with index funtion, we will use to fetch and load of all todos. It will also contains add todo view.
  • todos.store POST method with store function, we will have the logic of adding todo.
  • todos.edit GET method with edit function, we will use to fetch and load the view of edit todo.
  • todos.update PUT method with update function, we will use to update the todo.
  • todos.delete DELETE method with delete function, we will use to delete the todo.

Other than above routes, we will not be using in this tutorial.

Step 8: Create View File

What is View in Laravel?

The view usually contains all the frontend of the application aka HTML.

Laravel framework provides out of the box blade templating engine that’s helps to write HTML, PHP code easy to write plus provides tons of features.

How to create View in Laravel?

Since we want to create todo app, we will have two files.

In todo.blade.php, on the top we will have the add todo functionality and bottom we will display all the todos items.

In edit-todo.blade.php, we will load the existing todo title and status and allow you to change that.

Let’s create those two files now. Since there is no method to create view files via command, we have to manually go to resources/views the folder and create those files with the name of todo.blade.php and edit-todo.blade.php file.

All Views in laravel

Now let’s add the bootstrap 5 boilerplate in the both todo.blade.php and edit-todo.blade.php file.

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <title>Hello, world!</title>
</head>
<body>
<h1>Hello, world!</h1>


<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>

</body>
</html>

After that add the following code in both files after the body opening tag:

<div class="row justify-content-center mt-5">
    <div class="col-lg-6">
        @if(session()->has('success'))
            <div class="alert alert-success">
                {{ session()->get('success') }}
            </div>
        @endif

        @if ($errors->any())
            @foreach ($errors->all() as $error)
                <div class="alert alert-danger">
                    {{$error}}
                </div>
            @endforeach
        @endif
    </div>
</div>

The above code is nothing more but for capturing the errors and success messages.

You can see that we are using the if and foreach conditions that which blade templating engine provides out of the box to use PHP keywords directly in the HTML.

Whereas {{ }} is blade reversed keyword used to echo/ print something.

How cool it is that we write PHP code with HTML in a clean way.

When we access the controller function which contains the view. The blade engine renders that view into native PHP code and HTML code and shows us the output.

Cool now in the index function of app/Http/Controllers/TodoController link that todo.blade.php view file we created:

 public function index()
    {
        //
        return view('todo');
    }

Now if you visit the http://127.0.0.1:8000/todos in browser, you will see the Hello World.

Step 9: Lets write code for Create Operation

To do the create operation:

A) We need a form with the submit button in our todo.blade.php file.

B) Then that form will basically link that form to our POST route which is linked store function of the TodoController where will add the logic to store the todo in the database.

Don’t worry! If you don’t understand the above flow. You will be able to understand once we are doing it.

A) Create a form for collecting todo

In the todo.blade.php after the body opening tag add the following code for creating the form:

<div class="text-center mt-5">
    <h2>Add Todo</h2>

    <form class="row g-3 justify-content-center" method="POST" action="{{route('todos.store')}}">
        @csrf
        <div class="col-6">
            <input type="text" class="form-control" name="title" placeholder="Title">
        </div>
        <div class="col-auto">
            <button type="submit" class="btn btn-primary mb-3">Submit</button>
        </div>
    </form>
</div>

In the above code, you can see that we have added the text field and a button in the form.

Form method set to POST and action url to {{route('todos.store')}}.

Whereas the route keyword is used to access the route we want to link to.

In this case, we need to send request to the store function of TodoController which can be accessed by typing todos.store if you see the below screenshot.

How to see the routes in laravel

If you open the http://127.0.0.1:8000/todos in the browser, you will see something like this:

Add Todo View

B) Create a form for collecting todo

Now lets go to store function of the TodoController and add the following code:

 public function store(Request $request)
    {
        //
        $validator = Validator::make($request->all(), [
            'title' => 'required',
        ]);

        if ($validator->fails())
        {
            return redirect()->route('todos.index')->withErrors($validator);
        }

        Todo::create([
            'title'=>$request->get('title')
        ]);

               return redirect()->route('todos.index')->with('success', 'Inserted');

    }

In the above code, first we are validating the request using Laravel Validator functionality. We are validating that title is required always.

If it’s not present, return to route('todos.index') which is the main page of our application with the error.

If its present, then we are calling the Todo Model we created before with the create function to store the todo in the table of todos.

You can see that in create we have also passed title which have getting from the $request which contains all the variables passed to this function.

Note: Make sure to include the includes at the top of the TodoController.php file

use App\Models\Todo;
This will allow use to use the Todo Model

use Illuminate\Support\Facades\Validator;
This will allow us to use the Laravel Validator

So now if you don’t type anything in title and submit, you will see this error:

Add todo view with error message in laravel

If you type something in title field, you will see this success message:

Add todo view with success message in laravel

Which means that the todo is instead into the todos table.

Hurray! You have successfully completed your first operation of creating Todo.

Step 10: Lets write code for Read Operation

In the Read operation, we want to display all the todo we have in todos table.

A) First we will get all the todos in our index function of TodoController.

B) Then we will show all the todos in our todos.blade.php.

A) Get All todos in index function of TodoController

We need to get all the todos in our index function of TodoController. So we need to update our index function:

  public function index()
    {
        //
        $todos=Todo::all();
        return view('todo',compact('todos'));
    }

In the above code using the Todo Model, we are getting all the todos using all() function and storing them in $todos variable.

Then we are passing out the that todos variable to the view using compact.

The compact accept variable as the string itself.

Now the todo.blade.php, will have access to the all the todos.

B) Show all the todos in our todos.blade.php

In the todos.blade.php file, after the add todo code, add the following code:

<div class="text-center">
    <h2>All Todos</h2>
    <div class="row justify-content-center">
        <div class="col-lg-6">

            <table class="table table-bordered">
                <thead>
                <tr>
                    <th scope="col">#</th>
                    <th scope="col">Name</th>
                    <th scope="col">Created at</th>
                    <th scope="col">Status</th>
                    <th scope="col">Action</th>
                </tr>
                </thead>
                <tbody>

                @php $counter=1 @endphp

                @foreach($todos as $todo)
                    <tr>
                        <th>{{$counter}}</th>
                        <td>{{$todo->title}}</td>
                        <td>{{$todo->created_at}}</td>
                        <td>
                            @if($todo->is_completed)
                                <div class="badge bg-success">Completed</div>
                            @else
                                <div class="badge bg-warning">Not Completed</div>
                            @endif
                        </td>
                        <td>
                            <a class="btn btn-info">Edit</a>
                            <a class="btn btn-danger">Delete</a>
                        </td>
                    </tr>

                    @php $counter++; @endphp

                @endforeach
                </tbody>
            </table>
        </div>
    </div>
</div>

In the above code, first I have created the Bootstrap table, then created $counter variable using @php blade variable which allow us to write the PHP code.

Then we are looping through each todos (which have passed through the index function to the todos.blade.php in the Step A) using foreach PHP function.

You can see that we are loading the title of the todo item by $todo->title.

Then we have conditional rendering for the status that if $todo->is_completed is 1 then show complete and if its 0 then show not complete.

In the end of the table, we are incrementing the counter itself by using $counter++.

If you open the http://127.0.0.1:8000/todos in browser, you will see something like this:

Add Todo and All Todos Views in laravel

This means it showing all the todos we have in the database.

Step 11: Lets write code for Update Operation

To do an update operation:

A) First, we will change the URL of edit button in todos.blade.php.

B) Then, we link that view with edit function of TodoController with view edit-todo.blade.php.

C) Then, in edit-todo.blade.php we will create the form with title and status field in which we load the existing value and the user will be able to edit the title and status.

D) In update function, add logic for validation and updating the Todo .

A) Change URL of edit button in todos.blade.php

First of all, we need to change the edit button to following code in todos.blade.php.

                            <a href="{{route('todos.edit',['todo'=>$todo->id])}}" class="btn btn-info">Edit</a>

In the above code, we are changing the edit button in todos.blade.php to able to call the edit function in which we are passing the todo id which we want to edit.

B) Link Edit function with edit-todo.blade.php

In this step, we will link the edit function of TodoController to edit-todo.blade.php file. Add the following code in the edit function:

public function edit($id)
    {
        //

        $todo=Todo::where('id',$id)->first();
        return view('edit-todo',compact('todo'));
    }

In the edit function, you can see that we have id being passed, that id will be basically id of the todo item which details we want to load.

So we need to get data of that Todo using that id and that’s what we dong in the very first line of the edit function in the above code and storing it into $todo variable.

Then we passed that todo to the edit-todo.blade.php.

C) Create a form in edit-todo.blade.php

In this step, we will create the form in the edit-todo.blade.php. And we will link the form action with update function of TodoController.

We will add the following code after the starting tag of body:

<div class="text-center mt-5">
    <h2>Edit Todo</h2>
</div>

<form  method="POST" action="{{route('todos.update',['todo'=>$todo->id])}}">

    @csrf

    {{ method_field('PUT') }}

    <div class="row justify-content-center mt-5">

        <div class="col-lg-6">
            <div class="mb-3">
                <label class="form-label">Title</label>
                <input type="text" class="form-control" name="title" placeholder="Title" value="{{$todo->title}}">
            </div>
            <div class="mb-3">
                <label class="form-label">Status</label>
                <select name="is_completed" id="" class="form-control">
                    <option value="1" @if($todo->is_completed==1) selected @endif>Complete</option>
                    <option value="0" @if($todo->is_completed==0) selected @endif>Not Complete</option>
                </select>
            </div>

            <div class="mb-3">
                <button type="submit" class="btn btn-primary">Submit</button>
            </div>
    </div>

</form>

Notice in the above code, first we have form with title and status.

We are loading the title using $todo->title then we have status with select field in which have conditional rendering that if $todo->is_completed is 1 then select the select option Complete as selected and I the $todo->is_completed is 0 then select the select option Not Complete.

Then we have submit button.

In form action you can see that we have linked to the update method of TodoController.

Note: That update method is actually PUT method but we are using method of POST in this case.

The reason that HTML doesn’t have any way us to use the PUT and DELETE method.

Laravel solve this problem that if we want use the PUT method we can pass POST as the method and in body of form add method_field('PUT') which will allow us to use PUT method. How cool is that.

D) In update function, add logic for validation and updating the Todo

Now lets go to the update function of TodoController and add logic for validation and updating the Todo.

This is how the update function will look like:

 public function update(Request $request, $id)
    {


        $validator = Validator::make($request->all(), [
            'title' => 'required',
        ]);

        if ($validator->fails())
        {
            return redirect()->route('todos.edit',['todo'=>$id])->withErrors($validator);
        }



        $todo=Todo::where('id',$id)->first();
        $todo->title=$request->get('title');
        $todo->is_completed=$request->get('is_completed');
        $todo->save();

        return redirect()->route('todos.index')->with('success', 'Updated Todo');

    }

In the above code, first we validate the request using Laravel Validation, that the title is required. If the title not set, it will redirect to edit route otherwise the code will continue.

Then we are saving the title and the selected is_completed status using laravel save() function and redirecting back to the index function.

Now if click on the edit button, it will show something like this:

Edit View of Todo in laravel

So if the title is not present and you click on submit button it will show like this:

Edit View of Todo app with error message in laravel

And if the title is present and you click on the submit button it will redirect back to index the function which will load all todos with todos.blade.php view.

Add todo and All todo Todo app with in laravel

Step 12: Lets write code for Delete Operation

In order to perform the delete operation:

A) We need to assign the Delete Button the destory function of the TodoController.

B) Add GET method route that will call destory function of TodoController .

C) In Destory function, add logic to Delete Todo.

A) Assign Delete Button Delete function

In this very first step, we will assign the Delete button to call the destory function.

So we will change the Delete Button in todos.blade.php.

                            <a href="{{route('todos.destory',['todo'=>$todo->id])}}" class="btn btn-danger">Delete</a>

In the above code, we are assigning the destroy function and passing the todo id which we want to delete.

B) Add GET method route that will call destory function of TodoController

The destroy function is actually DELETE method. Since we cannot call the DELETE method using HTML.

Add the following code in routes/web.php:

Route::get('todos/{todo}', [\App\Http\Controllers\TodoController::class,'destroy'])->name('todos.destory');

In the above code, we convert that DELETE to be GET method in case of destroy function.

So for that purpose we had add new method GET route for delete that will basically call the destroy function.

C) In Destory function, add logic to Delete Todo

In this step, we will add logic to delete Todo in the destory function.

Add the following code:

  public function destroy($id)
    {
        Todo::where('id',$id)->delete();
        return redirect()->route('todos.index')->with('success', 'Deleted Todo');
    }

You can see that in the above code, that in the first line we passing id of the todo Item we want to delete and then deleting it using laravel delete() function.

Then we are redirecting to the index function with message of Deleted Todo.

So if you click on Delete Button, it will show something like this:

Hurray! With that we have completed all 4 CRUD operations.

Full Code

1- Full Code of Route/web.php file

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::resource('todos', \App\Http\Controllers\TodoController::class);
Route::get('todos/{todo}', [\App\Http\Controllers\TodoController::class,'destroy'])->name('todos.destory');

2- Full Code for todos.blade.php file

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <title>Hello, world!</title>

</head>
<body>

<div class="row justify-content-center mt-5">
    <div class="col-lg-6">
        @if(session()->has('success'))
            <div class="alert alert-success">
                {{ session()->get('success') }}
            </div>
        @endif

        @if ($errors->any())
            @foreach ($errors->all() as $error)
                <div class="alert alert-danger">
                    {{$error}}
                </div>
            @endforeach
        @endif
    </div>
</div>

<div class="text-center mt-5">
    <h2>Add Todo</h2>

    <form class="row g-3 justify-content-center" method="POST" action="{{route('todos.store')}}">
        @csrf
        <div class="col-6">
            <input type="text" class="form-control" name="title" placeholder="Title">
        </div>
        <div class="col-auto">
            <button type="submit" class="btn btn-primary mb-3">Submit</button>
        </div>
    </form>
</div>

<div class="text-center">
    <h2>All Todos</h2>
    <div class="row justify-content-center">
        <div class="col-lg-6">

            <table class="table table-bordered">
                <thead>
                <tr>
                    <th scope="col">#</th>
                    <th scope="col">Name</th>
                    <th scope="col">Created at</th>
                    <th scope="col">Status</th>
                    <th scope="col">Action</th>
                </tr>
                </thead>
                <tbody>

                @php $counter=1 @endphp

                @foreach($todos as $todo)
                    <tr>
                        <th>{{$counter}}</th>
                        <td>{{$todo->title}}</td>
                        <td>{{$todo->created_at}}</td>
                        <td>
                            @if($todo->is_completed)
                                <div class="badge bg-success">Completed</div>
                            @else
                                <div class="badge bg-warning">Not Completed</div>
                            @endif
                        </td>
                        <td>
                            <a href="{{route('todos.edit',['todo'=>$todo->id])}}" class="btn btn-info">Edit</a>
                            <a href="{{route('todos.destory',['todo'=>$todo->id])}}" class="btn btn-danger">Delete</a>
                        </td>
                    </tr>

                    @php $counter++; @endphp

                @endforeach
                </tbody>
            </table>
        </div>
    </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>

</body>
</html>

3- Full Code for edit-todo.blade.php file

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <title>Hello, world!</title>

</head>
<body>


<div class="row justify-content-center mt-5">
    <div class="col-lg-6">
        @if(session()->has('success'))
            <div class="alert alert-success">
                {{ session()->get('success') }}
            </div>
        @endif

        @if ($errors->any())
            @foreach ($errors->all() as $error)
                <div class="alert alert-danger">
                    {{$error}}
                </div>
            @endforeach
        @endif
    </div>
</div>

<div class="text-center mt-5">
    <h2>Edit Todo</h2>
</div>

<form  method="POST" action="{{route('todos.update',['todo'=>$todo->id])}}">

    @csrf

    {{ method_field('PUT') }}

    <div class="row justify-content-center mt-5">

        <div class="col-lg-6">
            <div class="mb-3">
                <label class="form-label">Title</label>
                <input type="text" class="form-control" name="title" placeholder="Title" value="{{$todo->title}}">
            </div>
            <div class="mb-3">
                <label class="form-label">Status</label>
                <select name="is_completed" id="" class="form-control">
                    <option value="1" @if($todo->is_completed==1) selected @endif>Complete</option>
                    <option value="0" @if($todo->is_completed==0) selected @endif>Not Complete</option>
                </select>
            </div>

            <div class="mb-3">
                <button type="submit" class="btn btn-primary">Submit</button>
            </div>
    </div>

</form>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>


</body>
</html>

4- Full Code for TodoController file

<?php

namespace App\Http\Controllers;

use App\Models\Todo;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class TodoController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //

        $todos=Todo::all();
        return view('todo',compact('todos'));

    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //

        $validator = Validator::make($request->all(), [
            'title' => 'required',
        ]);

        if ($validator->fails())
        {
            return redirect()->route('todos.index')->withErrors($validator);
        }

        Todo::create([
            'title'=>$request->get('title')
        ]);

        return redirect()->route('todos.index')->with('success', 'Inserted');

    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //

        $todo=Todo::where('id',$id)->first();
        return view('edit-todo',compact('todo'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {


        $validator = Validator::make($request->all(), [
            'title' => 'required',
        ]);

        if ($validator->fails())
        {
            return redirect()->route('todos.edit',['todo'=>$id])->withErrors($validator);
        }



        $todo=Todo::where('id',$id)->first();
        $todo->title=$request->get('title');
        $todo->is_completed=$request->get('is_completed');
        $todo->save();

        return redirect()->route('todos.index')->with('success', 'Updated Todo');

    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        Todo::where('id',$id)->delete();
        return redirect()->route('todos.index')->with('success', 'Deleted Todo');
    }
}

Conclusion

Hope in the above article, you have learned today how to do the CRUD (Create Read Update and Delete) Operation in laravel 9 using Bootstrap 5 for Todo App.

The above crash course has been created by keeping beginners in mind so every part of the above tutorial explained step by step.

Let me know if you have any questions in the comments, I will see you in the next one 🙂 See yaa.

Write a Reply or Comment

Your email address will not be published. Required fields are marked *


Icon