Build a Simple To-Do List Application with PHP & Ajax
To-do lists are a great way to allow users to manage their daily tasks. User can add/update their do items, close the list items when completed, and also remove these permanently from a complete list
In this tutorial, we will build our own Do-list application with Ajax, PHP and MySQL.This is a very simple example, you can just copy paste and change according to your requirement.
Before started to implement the To-Do List Application with PHP, look files structure:
- build-to-do-list-application-with-php-mysql-ajax
- css
- style.css
- todo.css
- js
- todo.js
- templates
- header.php
- footer.php
- class
- DBConnection.php
- Task.php
- index.php
- action.php
- css
Step 1: Create the database and Table
For this tutorial, you need a MySQL database with the following table:
1 2 3 4 5 6 7 8 9 10 11 12 |
CREATE TABLE `todo_list` ( `id` int(11) NOT NULL COMMENT 'Primary Key', `task` mediumtext NOT NULL, `status` int(1) DEFAULT 0 COMMENT '0=Active, 1=Done, 3=Delete ', `created` datetime NOT NULL DEFAULT current_timestamp() ) ENGINE=InnoDB DEFAULT CHARSET=latin1; ALTER TABLE `todo_list` ADD PRIMARY KEY (`id`); ALTER TABLE `todo_list` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key'; |
Step 2: Database Connection class
Create a controller file named DBConnection.php inside “class/” folder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?php /** * @package DBConnection * * @author TechArise Team * * @email info@techarise.com * */ // Database Connection class DBConnection { private $_dbHostname = "localhost"; private $_dbName = "demo_DB"; private $_dbUsername = "root"; private $_dbPassword = ""; private $_con; public function __construct() { try { $this->_con = new PDO("mysql:host=$this->_dbHostname;dbname=$this->_dbName", $this->_dbUsername, $this->_dbPassword); $this->_con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $e) { echo "Connection failed: " . $e->getMessage(); } } // return Connection public function returnConnection() { return $this->_con; } } ?> |
Step 3: Create a class file
Create a class file named Task.php inside “class/” folder.
- The Task class handles the task process.
__construct()
– Loads the required class.createTask()
– Insert recored in databaseupdateTask()
– Update record in databasegetAllTask()
– Get record from databasedeleteTask()
– Delete record from database
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
<?php /** * @package Task class * * @author TechArise Team * * @email info@techarise.com * */ // include connection class include("DBConnection.php"); // Task class Task { protected $db; private $_taskID; private $_item; private $_status; public function setTaskID($taskID) { $this->_taskID = $taskID; } public function setItem($item) { $this->_item = $item; } public function setStatus($status) { $this->_status = $status; } // __construct public function __construct() { $this->db = new DBConnection(); $this->db = $this->db->returnConnection(); } // create Task public function createTask() { try { $sql = 'INSERT INTO todo_list (task, status) VALUES (:task, :status)'; $data = [ 'task' => $this->_item, 'status' => $this->_status, ]; $stmt = $this->db->prepare($sql); $stmt->execute($data); $status = $this->db->lastInsertId(); return $status; } catch (Exception $err) { die("Oh noes! There's an error in the query! ".$err); } } // update Task public function updateTask() { try { $sql = "UPDATE todo_list SET status=:status WHERE id=:task_id"; $data = [ 'status' =>$this->_status, 'task_id' => $this->_taskID ]; $stmt = $this->db->prepare($sql); $stmt->execute($data); $status = $stmt->rowCount(); return $status; } catch (Exception $err) { die("Oh noes! There's an error in the query! " . $err); } } // getAll Task public function getAllTask() { try { $sql = "SELECT id, task, status FROM todo_list WHERE status != :status"; $stmt = $this->db->prepare($sql); $data = [ 'status' => $this->_status ]; $stmt->execute($data); $result = $stmt->fetchAll(\PDO::FETCH_ASSOC); return $result; } catch (Exception $err) { die("Oh noes! There's an error in the query! " . $err); } } // delete Task public function deleteTask() { try { $sql = "DELETE FROM todo_list WHERE id=:task_id"; $stmt = $this->db->prepare($sql); $data = [ 'task_id' => $this->_taskID ]; $stmt->execute($data); $status = $stmt->rowCount(); return $status; } catch (Exception $err) { die("Oh noes! There's an error in the query! " . $err); } } } ?> |
Step 4: Create action file named
action.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?php include_once 'class/Task.php'; $task = new Task(); $post = $_POST; $json = array(); // update functionality if(!empty($post['action']) && $post['action']=="create") { $task->setItem($post['item']); $task->setStatus(0); $status = $task->createTask(); if(!empty($status)){ $json['msg'] = 'success'; $json['task_id'] = $status; } else { $json['msg'] = 'failed'; $json['task_id'] = ''; } header('Content-Type: application/json'); echo json_encode($json); } // update functionality if(!empty($post['action']) && $post['action']=="update") { $task->setTaskID($post['task_id']); $task->setStatus($post['status']); $status = $task->updateTask(); if(!empty($status)){ $json['msg'] = 'success'; } else { $json['msg'] = 'failed'; } header('Content-Type: application/json'); echo json_encode($json); } // delete functionality if(!empty($post['action']) && $post['action']=="delete") { $task->setTaskID($post['task_id']); $status = $task->deleteTask(); if(!empty($status)){ $json['msg'] = 'success'; } else { $json['msg'] = 'failed'; } header('Content-Type: application/json'); echo json_encode($json); } ?> |
Step 5: Create HTML file named
index.php
We will create HTML file with an input and submit button to add and list Do-list items with out refresh page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<?php include_once 'class/Task.php'; $task = new Task(); $task->setStatus(2); $taskInfo = $task->getAllTask(); include('templates/header.php'); ?> <section class="showcase"> <div class="container"> <div class="pb-2 mt-4 mb-2 border-bottom"> <h2>Build a Simple To-Do List Application with PHP & Ajax</h2> </div> <div class="page-content page-container" id="page-content"> <div class="padding"> <div class="row container d-flex justify-content-center"> <div class="col-lg-12"> <div class="card px-3"> <div class="card-body"> <h4 class="card-title">Todo list</h4> <div class="add-items d-flex"> <input type="text" class="form-control todo-list-input" placeholder="What do you need to do today?"> <button class="add btn btn-primary font-weight-bold todo-list-add-btn">Add</button> </div> <div class="list-wrapper"> <ul class="d-flex flex-column-reverse todo-list"> <?php foreach($taskInfo as $key=>$element) { if(!empty($element['status']) && $element['status']==1){ $class = 'class="completed"'; $checked = 'checked="checked"'; } else { $class = ''; $checked = ''; } ?> <li <?php print $class; ?>> <div class="form-check"> <label class="form-check-label"> <input class="checkbox" type="checkbox" <?php print $checked; ?> data-utaskid="<?php print $element['id']; ?>"> <?php print $element['task']?> <i class="input-helper"></i></label> </div> <i data-dtaskid="<?php print $element['id']; ?>" class="remove fa fa-times"></i> </li> <?php } ?> </ul> </div> </div> </div> </div> </div> </div> </div> </div> </section> <?php include('templates/footer.php');?> |
Step 6: Create JavaScript file named
todo.js
We will handle AJAX request
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
jQuery(document).ready(function() { var todoListItem = jQuery('.todo-list'); var todoListInput = jQuery('.todo-list-input'); // create functionality jQuery('.todo-list-add-btn').on("click", function(event) { event.preventDefault(); var action = 'create'; var item = jQuery(this).prevAll('.todo-list-input').val(); var bindHTML = ''; jQuery.ajax({ type:'POST', url:'action.php', data:{action:action, item:item}, dataType:'json', success: function (json) { if (item) { bindHTML+= '<li>'; bindHTML+= '<div class="form-check">'; bindHTML+= '<label class="form-check-label">'; bindHTML+= '<input class="checkbox" type="checkbox" data-utaskid="'+json.task_id+'" />' + item; bindHTML+= '<i class="input-helper"></i>'; bindHTML+= '</label>'; bindHTML+= '</div>'; bindHTML+= '<i data-dtaskid="'+json.task_id+'" class="remove fa fa-times"></i>'; bindHTML+= '</li>'; todoListItem.append(bindHTML); todoListInput.val(""); } }, error: function (xhr, ajaxOptions, thrownError) { console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); } }); }); // update functionality todoListItem.on('change', '.checkbox', function() { var action = 'update'; var task_id = jQuery(this).data('utaskid'); if (jQuery(this).attr('checked')) { jQuery(this).removeAttr('checked'); var status = 0; } else { jQuery(this).attr('checked', 'checked'); var status = 1; } jQuery.ajax({ type:'POST', url:'action.php', data:{action:action, task_id:task_id, status:status}, dataType:'json', success: function (json) { return true; }, error: function (xhr, ajaxOptions, thrownError) { console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); } }); jQuery(this).closest("li").toggleClass('completed'); }); // delete functionality todoListItem.on('click', '.remove', function() { var action = 'delete'; var task_id = jQuery(this).data('dtaskid'); jQuery.ajax({ type:'POST', url:'action.php', data:{action:action, task_id:task_id}, dataType:'json', success: function (json) { return true; }, error: function (xhr, ajaxOptions, thrownError) { console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); } }); jQuery(this).parent().remove(); }); }); |
Create files named (header.php and footer.php)
This file contains the header and footer section of the webpage. The Bootstrap library is used to provide a better UI, so, include it in the header and footer section.
header.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>Generate QR Codes using PHP | Tech Arise</title> <!-- Bootstrap core CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css" /> <!-- Custom fonts for this template --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.7.2/css/all.min.css" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.css" /> <link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,300italic,400italic,700italic" rel="stylesheet" type="text/css"> <!-- Custom styles for this template --> <link href="css/style.css" rel="stylesheet"> <link href="css/todo.css" rel="stylesheet"> </head> <body> <!-- Navigation --> <nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top header-bg-dark" style="background: ##FFFFFF!;"> <div class="container"> <a class="navbar-brand font-weight-bold" href="https://techarise.com"><h1>Tech Arise</h1></a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarResponsive"> <ul class="navbar-nav ml-auto"> <li class="nav-item active"> <a class="nav-link" href="https://techarise.com">Home <span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="https://techarise.com/php-free-script-demos/">Live Demo</a> </li> </ul> </div> </div> </nav> |
footer.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
<!-- Footer --> <footer class="footer bg-light footer-bg-dark"> <div class="container"> <div class="row"> <div class="col-lg-6 h-100 text-center text-lg-left my-auto"> <ul class="list-inline mb-2"> <li class="list-inline-item"> <a href="#">About</a> </li> <li class="list-inline-item">⋅</li> <li class="list-inline-item"> <a href="#">Contact</a> </li> <li class="list-inline-item">⋅</li> <li class="list-inline-item"> <a href="#">Terms of Use</a> </li> <li class="list-inline-item">⋅</li> <li class="list-inline-item"> <a href="#">Privacy Policy</a> </li> </ul> <p class="text-muted small mb-4 mb-lg-0">Copyright © 2011 - <?php print date('Y', time());?> <a href="https://techarise.com/">TECHARISE.COM</a> All rights reserved.</p> </div> <div class="col-lg-6 h-100 text-center text-lg-right my-auto"> <ul class="list-inline mb-0"> <li class="list-inline-item mr-3"> <a href="#"> <i class="fab fa-facebook fa-2x fa-fw"></i> </a> </li> <li class="list-inline-item mr-3"> <a href="#"> <i class="fab fa-twitter-square fa-2x fa-fw"></i> </a> </li> <li class="list-inline-item"> <a href="#"> <i class="fab fa-instagram fa-2x fa-fw"></i> </a> </li> </ul> </div> </div> </div> </footer> <!-- Bootstrap core JavaScript --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script> <script src="js/todo.js"></script> </body> </html> |