Building a To-do List with Ajax

7 min read

(For more resources related to this topic, see here.)

Creating and migrating our to-do list’s database

As you know, migrations are very helpful to control development steps. We’ll use migrations in this article.

To create our first migration, type the following command:

php artisan migrate:make create_todos_table --table=todos --create

When you run this command, Artisan will generate a migration to generate a database table named todos.

Now we should edit the migration file for the necessary database table columns. When you open the folder migration in app/database/ with a file manager, you will see the migration file under it.

Let’s open and edit the file as follows:

<?php use IlluminateDatabaseMigrationsMigration; class CreateTodosTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('todos', function(Blueprint $table){ $table->create(); $table->increments("id"); $table->string("title", 255); $table->enum('status', array('0', '1'))->default('0'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop("todos"); } }

To build a simple TO-DO list, we need five columns:

  • The id column will store ID numbers of to-do tasks
  • The title column will store a to-do task’s title
  • The status column will store statuses of the tasks
  • The created_at and updated_at columns will store the created and updated dates of tasks

If you write $table->timestamps() in the migration file, Laravel’s migration class automatically creates created_at and updated_at columns. As you know, to apply migrations, we should run the following command:

php artisan migrate

After the command is run, if you check your database, you will see that our todos table and columns have been created. Now we need to write our model.

Creating a todos model

To create a model, you should open the app/models/ directory with your file manager. Create a file named Todo.php under the directory and write the following code:

<?php class Todo extends Eloquent { protected $table = 'todos'; }

Let’s examine the Todo.php file.

As you see, our Todo class extends an Eloquent model, which is the ORM (Object Relational Mapper) database class of Laravel.

The protected $table = ‘todos’; code tells Eloquent about our model’s table name. If we don’t set the table variable, Eloquent accepts the plural version of the lower case model name as table name. So this isn’t required technically.

Now, our application needs a template file, so let’s create it.

Creating the template

Laravel uses a template engine that is called blade for static and application template files. Laravel calls the template files from the app/views/ directory, so we need to create our first template under this directory.

  1. Create a file with the name index.blade.php.
  2. The file contains the following code:

    <html> <head> <title>To-do List Application</title> <link rel="stylesheet" href="assets/css/style.css"> <!--[if lt IE 9]><script src = "//"> </script><![endif]--> </head> <body> <div class="container"> <section id="data_section" class="todo"> <ul class="todo-controls"> <li><img src = "/assets/img/add.png" width="14px" onClick="show_form('add_task');" /></li> </ul> <ul id="task_list" class="todo-list"> @foreach($todos as $todo) @if($todo->status) <li id="{{$todo->id}}" class="done"> <a href="#" class="toggle"></a> <span id="span_{{$todo->id}}">{ {$todo->title}}</span> <a href="#" onClick="delete_task('{{$todo->id}}');" class="icon-delete">Delete</a> <a href="#" onClick="edit_task('{{$todo->id}}', '{{$todo->title}}');" class="icon-edit">Edit</a></li> @else <li id="{{$todo->id}}"><a href="#" onClick="task_done('{{$todo->id}}');" class="toggle"></a> <span id="span_{ {$todo->id}}">{{$todo->title}}</span> <a href="#" onClick="delete_task('{ {$todo->id}}');" class= "icon-delete">Delete</a> <a href="#" onClick="edit_task('{ {$todo->id}}','{{$todo->title}}');" class="icon-edit">Edit</a></li> @endif @endforeach </ul> </section> <section id="form_section"> <form id="add_task" class="todo" style="display:none"> <input id="task_title" type="text" name="title" placeholder="Enter a task name" value=""/> <button name="submit">Add Task</button> </form> <form id="edit_task" class="todo" style="display:none"> <input id="edit_task_id" type="hidden" value="" /> <input id="edit_task_title" type="text" name="title" value="" /> <button name="submit">Edit Task</button> </form> </section> </div> <script src = " jquery-latest.min.js"type="text/javascript"></script> <script src = "assets/js/todo.js" type="text/javascript"></script> </body> </html>

The preceding code may be difficult to understand if you’re writing a blade template for the first time, so we’ll try to examine it. You see a foreach loop in the file. This statement loops our todo records.

We will provide you with more knowledge about it when we are creating our controller in this article.

If and else statements are used for separating finished and waiting tasks. We use if and else statements for styling the tasks.

We need one more template file for appending new records to the task list on the fly. Create a file with the name ajaxData.blade.php under app/views/ folder. The file contains the following code:

@foreach($todos as $todo) <li id="{{$todo->id}}"><a href="#" onClick="task_done('{{$todo- >id}}');" class="toggle"></a> <span id="span_{{$todo >id}}">{{$todo->title}}</span> <a href="#" onClick="delete_task('{{$todo->id}}');" class="icon delete">Delete</a> <a href="#" onClick="edit_task('{{$todo >id}}','{{$todo->title}}');" class="icon-edit">Edit</a></li> @endforeach

Also, you see the /assets/ directory in the source path of static files. When you look at the app/views directory, there is no directory named assets. Laravel separates the system and public files. Public accessible files stay under your public folder in root. So you should create a directory under your public folder for asset files.

We recommend working with these types of organized folders for developing tidy and easy-to-read code. Finally you see that we are calling jQuery from its main website. We also recommend this way for getting the latest, stable jQuery in your application.

You can style your application as you wish, hence we’ll not examine styling code here. We are putting our style.css files under /public/assets/css/.

For performing Ajax requests, we need JavaScript coding. This code posts our add_task and edit_task forms and updates them when our tasks are completed. Let’s create a JavaScript file with the name todo.js in /public/assets/js/. The files contain the following code:

function task_done(id){ $.get("/done/"+id, function(data) { if(data=="OK"){ $("#"+id).addClass("done"); } }); } function delete_task(id){ $.get("/delete/"+id, function(data) { if(data=="OK"){ var target = $("#"+id); target.hide('slow', function(){ target.remove(); }); } }); } function show_form(form_id){ $("form").hide(); $('#'+form_id).show("slow"); } function edit_task(id,title){ $("#edit_task_id").val(id); $("#edit_task_title").val(title); show_form('edit_task'); } $('#add_task').submit(function(event) { /* stop form from submitting normally */ event.preventDefault(); var title = $('#task_title').val(); if(title){ //ajax post the form $.post("/add", {title: title}).done(function(data) { $('#add_task').hide("slow"); $("#task_list").append(data); }); } else{ alert("Please give a title to task"); } }); $('#edit_task').submit(function() { /* stop form from submitting normally */ event.preventDefault(); var task_id = $('#edit_task_id').val(); var title = $('#edit_task_title').val(); var current_title = $("#span_"+task_id).text(); var new_title = current_title.replace(current_title, title); if(title){ //ajax post the form $.post("/update/"+task_id, {title: title}).done(function(data) { $('#edit_task').hide("slow"); $("#span_"+task_id).text(new_title); }); } else{ alert("Please give a title to task"); } });

Let’s examine the JavaScript file.

Subscribe to the weekly Packt Hub newsletter

* indicates required


Please enter your comment!
Please enter your name here