AJAX-ed Todo List With PHP, MySQL & jQuery

AJAX-ed Todo List With PHP, MySQL & jQuery

In this tutorial we are making a simple AJAX-ed Todo List App, with PHP, MySQL and jQuery. In the process we are going to demonstrate PHP’s OOP capabilities, play with jQuery UI and implement some nice AJAX functionality.

For a better understanding of the steps of this tutorial, you an go ahead and download the demo archive available from the button above.

Step 1 – PHP

As this is more of a developer-oriented tutorial, we are going to start with the PHP part. Unlike previous tutorials, this time we are leveraging the OOP features of PHP 5.

The author presumes you have a basic understanding of the core concepts behind object oriented programming, and PHP 5′s OOP implementation. For a quick reference, check out these pages of PHP’s documentation: OOP Basics, Static Methods, Exceptions, Magic Methods.

All of the functionality available to the end user – creating, editing, deleting and reordering the todo items – is implemented as different methods of a class, explained in detail below.

todo.class.php – Part 1

/* Defining the ToDo class */

class ToDo{

	/* An array that stores the todo item data: */

	private $data;

	/* The constructor */
	public function __construct($par){
		if(is_array($par))
			$this->data = $par;
	}

	/*
		This is an in-build "magic" method that is automatically called
		by PHP when we output the ToDo objects with echo.
	*/

	public function __toString(){

		// The string we return is outputted by the echo statement

		return '
			<li id="todo-'.$this->data['id'].'" class="todo">

				<div class="text">'.$this->data['text'].'</div>

				<div class="actions">
					<a href="" class="edit">Edit</a>
					<a href="" class="delete">Delete</a>
				</div>

			</li>';
	}

The constructor takes the array passed as a parameter and stores it in the $data property of the class. This array is a row fetched from the database with mysql_fetch_assoc() and contains the id and the text of the todo item.

After this is the magic __toString() method, which is called internally when we attempt to echo out an object of this class. The string it returns contains the markup used by each todo item – a <li> element with a unique id and a classname  “todo”, inside of which we have the text of the todo and the two action hyperlinks.

AJAX, jQuery & CSS3 To Do List

AJAX, jQuery & CSS3 To Do List

todo.class.php – Part 2

	/*
		The edit method takes the ToDo item id and the new text
		of the ToDo. Updates the database.
	*/

	public static function edit($id, $text){

		$text = self::esc($text);
		if(!$text) throw new Exception("Wrong update text!");

		mysql_query("	UPDATE tz_todo
						SET text='".$text."'
						WHERE id=".$id
					);

		if(mysql_affected_rows($GLOBALS['link'])!=1)
			throw new Exception("Couldn't update item!");
	}

	/*
		The delete method. Takes the id of the ToDo item
		and deletes it from the database.
	*/

	public static function delete($id){

		mysql_query("DELETE FROM tz_todo WHERE id=".$id);

		if(mysql_affected_rows($GLOBALS['link'])!=1)
			throw new Exception("Couldn't delete item!");
	}

	/*
		The rearrange method is called when the ordering of
		the todos is changed. Takes an array parameter, which
		contains the ids of the todos in the new order.
	*/

	public static function rearrange($key_value){

		$updateVals = array();
		foreach($key_value as $k=>$v)
		{
			$strVals[] = 'WHEN '.(int)$v.' THEN '.((int)$k+1).PHP_EOL;
		}

		if(!$strVals) throw new Exception("No data!");

		// We are using the CASE SQL operator to update the ToDo positions en masse:

		mysql_query("	UPDATE tz_todo SET position = CASE id
						".join($strVals)."
						ELSE position
						END");

		if(mysql_error($GLOBALS['link']))
			throw new Exception("Error updating positions!");
	}

The definition of the class continues with a number of static methods. Those are special methods, which can be accessed without the need of an object of the class to be created. For example, you can call the edit method by writing: ToDo::edit($par1,$par2).

Notice how we are using exceptions to handle errors. When an exception occurs the script execution halts and it is up to the rest of the script to catch it and output the appropriate status.

Also you may find interesting the way we are updating the database with the new positions of the todo items. We are using the CASE operator, available in MySQL.  This way, no matter how many todos are in the database, we execute only one query.

Saving queries and optimizing your scripts, although tedious, is hugely beneficial in the long run. You can read more about the CASE operator (among other interesting features) in MySQL’s official documentation.

todo.class.php – Part 3

	/*
		The createNew method takes only the text of the todo as a parameter,
		writes to the database and outputs the new todo back to
		the AJAX front-end.
	*/

	public static function createNew($text){

		$text = self::esc($text);
		if(!$text) throw new Exception("Wrong input data!");

		$posResult = mysql_query("SELECT MAX(position)+1 FROM tz_todo");

		if(mysql_num_rows($posResult))
			list($position) = mysql_fetch_array($posResult);

		if(!$position) $position = 1;

		mysql_query("INSERT INTO tz_todo SET text='".$text."', position = ".$position);

		if(mysql_affected_rows($GLOBALS['link'])!=1)
			throw new Exception("Error inserting TODO!");

		// Creating a new ToDo and outputting it directly:

		echo (new ToDo(array(
			'id'	=> mysql_insert_id($GLOBALS['link']),
			'text'	=> $text
		)));

		exit;
	}

	/*
		A helper method to sanitize a string:
	*/

	public static function esc($str){

		if(ini_get('magic_quotes_gpc'))
			$str = stripslashes($str);

		return mysql_real_escape_string(strip_tags($str));
	}

} // closing the class definition

Accessing static methods from the same class can easily be done with the self:: keyword. This way we are using the esc() method to sanitize the incoming user data.

Also notice the createNew() method. In it, after running the INSERT query on the database, we use the returned auto-assigned unique id with mysql_insert_id() and create a new todo object, which is then echoed out to the front end.

Now lets take a look at how this class is used.

demo.php – Part 1

// Select all the todos, ordered by position:
$query = mysql_query("SELECT * FROM `tz_todo` ORDER BY `position` ASC");

$todos = array();

// Filling the $todos array with new ToDo objects:

while($row = mysql_fetch_assoc($query)){
	$todos[] = new ToDo($row);
}

After including todo.class.php in demo.php, we select the todo items and loop through the MySQL result set, filling in the $todos array with objects.

demo.php – Part 2

// Looping and outputting the $todos array. The __toString() method
// is used internally to convert the objects to strings:

foreach($todos as $item){
	echo $item;
}

Later in the page, these objects are echoed out. Thanks to the __toString() method discussed above, all the markup is automatically generated, so we do not have to deal with any of that.

The front end issues a number of different AJAX calls. Making a separate file to handle each of them would be a bit of overkill, so the best solution is to group them in a single AJAX handling file. This is done in ajax.php, which you can see below.

ajax.php

$id = (int)$_GET['id'];

try{

	switch($_GET['action'])
	{
		case 'delete':
			ToDo::delete($id);
			break;

		case 'rearrange':
			ToDo::rearrange($_GET['positions']);
			break;

		case 'edit':
			ToDo::edit($id,$_GET['text']);
			break;

		case 'new':
			ToDo::createNew($_GET['text']);
			break;
	}

}
catch(Exception $e){
//	echo $e->getMessage();
	die("0");
}

echo "1";

With the help of a switch statement, we decide which of the static methods of the ToDo class to execute. If an error occurs in one of these methods, an exception is dispatched. Because the whole switch is enclosed in a try statement, execution of the script halts and control is passed to the catch statement, which outputs a zero and exits the script.

You could potentially echo (or write to a log) exactly what kind of error occurred by uncommenting line 26.

Step 2 – MySQL

The tz_todo table holds and assigns the unique ids of the todo items (via the auto_increment setting of the field), the position, the text and the dt_added timestamp.

Database Schema

Database Schema

You can find the SQL that will recreate the table in table.sql in the download archive. Also, if you plan to run the demo on your own server, don’t forget to fill in your login details in connect.php.

Step 3 – XHTML

As most of the markup is generated by PHP, we are left with taking care of the rest of the page’s XHTML. First we need to include jQuery, jQuery UI, and the stylesheets in the document. It is considered a good practice to include the stylesheets to the head section, and the JavaScript files right before the closing </body> tag.

<link rel="stylesheet" href="jquery-ui.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="styles.css" />

<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="jquery-ui.min.js"></script>
<script type="text/javascript" src="script.js"></script>

After this we can move on to coding the rest of the page.

demo.php

<div id="main">

	<ul class="todoList">

	<?php

		// Looping and outputting the $todos array. The __toString() method
		// is used internally to convert the objects to strings:

		foreach($todos as $item){
			echo $item;
		}

		?>

	</ul>

	<a id="addButton" class="green-button" href="">Add a ToDo</a>

</div>

<!-- This div is used as the base for the confirmation jQuery UI dialog box. Hidden by CSS. -->
<div id="dialog-confirm" title="Delete TODO Item?">Are you sure you want to delete this TODO item?</div>

Each todo is a li item inside of the todoList unordered list. This way, we can later use the sortable method of jQuery UI to easily convert it into an interactive sortable element. Also, in the process, we enhance the semantic value of the code.

Step 4 – CSS

Now lets move on to the styling of the todos. Only parts of the original stylesheet are given here for better readability. You can find the rest in styles.css in the download archive.

styles.css – Part 1

/* The todo items are grouped into an UL unordered list */

ul.todoList{
	margin:0 auto;
	width:500px;
	position:relative;
}

ul.todoList li{
	background-color:#F9F9F9;
	border:1px solid #EEEEEE;
	list-style:none;
	margin:6px;
	padding:6px 9px;
	position:relative;
	cursor:n-resize;

	/* CSS3 text shadow and rounded corners: */

	text-shadow:1px 1px 0 white;

	-moz-border-radius:6px;
	-webkit-border-radius:6px;
	border-radius:6px;
}

ul.todoList li:hover{
	border-color:#9be0f9;

	/* CSS3 glow effect: */
	-moz-box-shadow:0 0 5px #A6E5FD;
	-webkit-box-shadow:0 0 5px #A6E5FD;
	box-shadow:0 0 5px #A6E5FD;
}

The todoList ul is horizontally centered on the page and is assigned a relative positioning. The li elements inside it (the todo items) share a number of CSS3 rules. These, unfortunately, do not work in older browsers, but as they are solely for presentation purposes even browsers as old as IE6 can enjoy a fully working script, albeit not as pretty as intentioned.

styles.css – Part 2

/* The edit textbox */

.todo input{
	border:1px solid #CCCCCC;
	color:#666666;
	font-family:Arial,Helvetica,sans-serif;
	font-size:0.725em;
	padding:3px 4px;
	width:300px;
}

/* The Save and Cancel edit links: */

.editTodo{
	display:inline;
	font-size:0.6em;
	padding-left:9px;
}

.editTodo a{
	font-weight:bold;
}

a.discardChanges{
	color:#C00 !important;
}

a.saveChanges{
	color:#4DB209 !important;
}

In the second part of the code we style the input text box, shown when the todo item is edited, and the save and cancel links.

jQuery UI Dialog Box

jQuery UI Dialog Box

Step 5 – jQuery

Moving to the JavaScript code. Here we are using two of jQuery UI’s user interface components – sortable, and dialog. These alone save us at least a couple of hours of development time, which is one of the benefits of using a nicely thought out library like jQuery.

script.js – Part 1

$(document).ready(function(){
	/* The following code is executed once the DOM is loaded */

	$(".todoList").sortable({
		axis		: 'y',				// Only vertical movements allowed
		containment	: 'window',			// Constrained by the window
		update		: function(){		// The function is called after the todos are rearranged

			// The toArray method returns an array with the ids of the todos
			var arr = $(".todoList").sortable('toArray');

			// Striping the todo- prefix of the ids:

			arr = $.map(arr,function(val,key){
				return val.replace('todo-','');
			});

			// Saving with AJAX
			$.get('ajax.php',{action:'rearrange',positions:arr});
		}
	});

	// A global variable, holding a jQuery object
	// containing the current todo item:

	var currentTODO;

	// Configuring the delete confirmation dialog
	$("#dialog-confirm").dialog({
		resizable: false,
		height:130,
		modal: true,
		autoOpen:false,
		buttons: {
			'Delete item': function() {

				$.get("ajax.php",{"action":"delete","id":currentTODO.data('id')},function(msg){
					currentTODO.fadeOut('fast');
				})

				$(this).dialog('close');
			},
			Cancel: function() {
				$(this).dialog('close');
			}
		}
	});

To display the dialog, we need to have a base div, which is going to be converted to a dialog. The contents of the div is going to be displayed as the text of the dialog, and the contents of the title attribute of the div will become the title of the dialog window. You can find this div (id=dialog-confirm) in demo.php.

script.js – Part 2

	// When a double click occurs, just simulate a click on the edit button:
	$('.todo').live('dblclick',function(){
		$(this).find('a.edit').click();
	});

	// If any link in the todo is clicked, assign
	// the todo item to the currentTODO variable for later use.

	$('.todo a').live('click',function(e){

		currentTODO = $(this).closest('.todo');
		currentTODO.data('id',currentTODO.attr('id').replace('todo-',''));

		e.preventDefault();
	});

	// Listening for a click on a delete button:

	$('.todo a.delete').live('click',function(){
		$("#dialog-confirm").dialog('open');
	});

	// Listening for a click on a edit button

	$('.todo a.edit').live('click',function(){

		var container = currentTODO.find('.text');

		if(!currentTODO.data('origText'))
		{
			// Saving the current value of the ToDo so we can
			// restore it later if the user discards the changes:

			currentTODO.data('origText',container.text());
		}
		else
		{
			// This will block the edit button if the edit box is already open:
			return false;
		}

		$('<input type="text">').val(container.text()).appendTo(container.empty());

		// Appending the save and cancel links:
		container.append(
			'<div class="editTodo">'+
				'<a class="saveChanges" href="">Save</a> or <a class="discardChanges" href="">Cancel</a>'+
			'</div>'
		);

	});

Notice the use of the jQuery live() method to bind events. We are using live(), instead of bind(), because live() can listen for events on any elements, even those who do not yet exist. This way we make sure that all the todo items added in the future to the page by the user, will also trigger the same event handlers, as the currently existing ones.

script.js – Part 3

	// The cancel edit link:

	$('.todo a.discardChanges').live('click',function(){
		currentTODO.find('.text')
					.text(currentTODO.data('origText'))
					.end()
					.removeData('origText');
	});

	// The save changes link:

	$('.todo a.saveChanges').live('click',function(){
		var text = currentTODO.find("input[type=text]").val();

		$.get("ajax.php",{'action':'edit','id':currentTODO.data('id'),'text':text});

		currentTODO.removeData('origText')
					.find(".text")
					.text(text);
	});

	// The Add New ToDo button:

	var timestamp;
	$('#addButton').click(function(e){

		// Only one todo per 5 seconds is allowed:
		if(Date.now() - timestamp<5000) return false;

		$.get("ajax.php",{'action':'new','text':'New Todo Item. Doubleclick to Edit.'},function(msg){

			// Appending the new todo and fading it into view:
			$(msg).hide().appendTo('.todoList').fadeIn();
		});

		// Updating the timestamp:
		timestamp = Date.now();

		e.preventDefault();
	});

}); // Closing $(document).ready()

In the last part of the code we are binding events to the Save and Cancel links, which are added to the todo when editing it. We also set up an event listener for the “Add” button. Notice how we prevent flooding by limiting the submit rate of new todos to one every 5 seconds.

With this our AJAX-ed To Do List is complete!

Conclusion

Today we created a simple AJAX enabled ToDo web script with PHP, MySQL and jQuery. You can use it to create your own task management application or turn it into a fully fledged web app.

What do you think? How would you modify this code?

by Martin Angelov

Martin is a web developer with an eye for design from Bulgaria. He founded Tutorialzine in 2009 and publishes new tutorials weekly.

Tutorials

76 Comments

  1. l3gion says:

    Awesome work, as usual.

    PS: Don't buy an iPad..ROTFL :P

  2. Moe says:

    this is really neat !!!

    well done buddy & thanks for sharing :-)

  3. Remus says:

    nice work i like :)

  4. Brant says:

    One of the best tutorials I've ever read.

    However, I noticed that you placed your js and css components near the closing body tag. Is this the way it should be done now? And why is that?

  5. David says:

    Very cool tut. Keep up the good work!

  6. iMayne says:

    Since work! I'll see if I will have use for it.

  7. Paweł P. says:

    Good article, good work but example dosn't work
    correctly in Opera (sorting). Best regards!

  8. Antonio says:

    Cool, but it's not usable on last Opera (v10.51) though.
    Btw that's a tutorial, so just... thanks.

  9. Martin Angelov says:

    Thanks for the comments folks!

    @ Brant
    Including the script tags at the bottom of the page lets the browser display the design without having to wait for the scripts to download first. Doesn't look like much, but loading seems faster because you don't wait at a blank screen for the site to load.

    This applies only to script tags, stylesheets still have to be in the head section.

    @ Pawel, @Antonio

    Added a simple fix for the Opera browser (this is actually an internal jQuery UI bug I wasn't aware of). You can check the demo and re-download the zip.

  10. Artur says:

    Tutorial muito legal. Parabéns... Very Good.

    thanks,
    Artur

  11. O'Ryan says:

    Sweetness! this is a pretty awesome Tutorial!

    I really wish there was a done option though rather than just deleting it. It's just satisfying to be able to cross out a task after completing it.

    Hmm i may just have to add that.... maybe a check box or something, and an extra DB field :)

    Thanks for all the sweet Code and instruction!!!

  12. Al says:

    Amazing work! Thanks for sharing!

  13. Beben says:

    very very interesting...
    thanks for share with us...hihihi :D

  14. Cagin Donmez says:

    really great, everytime you guys post something,I'm starting to think about what can I do to use these stuff :D .Cuz theyre actually really cool :D

  15. Dustin says:

    This looks really Great! Thanks

    Would it be possible to have multiple columns and drag and sort between them as well? How can this be accomplished? I would like to sort within a column and betwen several columns while storing the positions in the database and having the ability to edit add and delete just as you have demonstrated

    Thanks.

  16. Darien says:

    nice tut keep up the good work guys

  17. SD webmagic says:

    thanx a lot really great Tutorial.
    and this is the first simple kinds of Tutorials i read and contains OOP.
    really thanx.

  18. Ricardo Verhaeg says:

    Nicely done!! I'll add some tags to it and use as my chrome startpage!
    great work!

  19. Richard says:

    Great tutorial - thank you very much!!

  20. Dustin says:

    Hi Martin,

    Great work here!

    I am new to AJAX scripting and I have tried to add a second column to sort between them but I can't seem to make this work correctly. I am not sure how to save the column information into the database or where to get the column information in order to save it. Is there an easy solution for this modification?

    I would like to sort between columns and also be able to sort within a column while having the functionality you provided with add, edit, sort and delete.

    Any help would be greatly appreciated.

    Thanks again for providing your script to us. :)

  21. Dustin says:

    Does anyone have an idea for adding a couple of additional lists and sorting between them with the functionality in this code?

    I think this code will be perfect if I can just include a few more lists on the same page. I am not a very good script person but I do understand the value of this design and it is awsome.

    I am trying to build a middle school team selection web interface.
    Basically, a coach could have a database and enter the members name and then sort it between several team names. If new players have an interest, the coach could add names on the fly or remove them if a member leaves.

    I would use the add todo button to build out the names of players into a universal column and pull them into the respective team lists based on the coach's preferences.

    Thanks

  22. nanat says:

    very awesome script.. all package 3 in one just like nescafe.. amazing..

    im trying to understand the whole script but it so complicated than i thought. its been to 2days from now searching for each meaning of the function but its all worthy.

  23. k9huey says:

    I love the script and I am using it but I changed one thing. The buttons show over the text so I found the CSS that places the buttons and gave them a negitive value
    /* The edit and delete buttons */

    .todo .actions{
    position:absolute;
    right:-50px;
    top:6px;
    }

    That fixed that but know how do I fix this.
    IF there are more then 16 items in the list the drag does not work properly. Say you grab item 20 it will jump to position 16 and you can go up with it but not down. Also say you grab item 10 you can not go past position 16.

    Any Ideas?

  24. Sabrina says:

    Hey,

    Very nice tutorial... There's just one thing. how can i put a max length on it because when i type .. its te big voor the frame..

  25. Jan says:

    Beautiful tutorial and design,

    Is it an idea to make this also an iphone tutorial.
    Cause double-click don't work on a iphone.

    Thanks

    Jan.

  26. shpyo says:

    Nice. You solved my problem with creating similar script. Thanks :)

  27. Nilesh says:

    Loved it, will ad on for the users on my site to use saperately!

  28. bakazero says:

    nice. very nice..
    easy to learn too. thanks!

  29. hugo says:

    Hi!
    Great tutorial!

    Iv been testing it out and almost got it working with two input fields...
    Im getting 2 rows for each todo from the database, and i want to be able to update both.
    Im not sure how to do this because of the currentData is messing it up and confusing both inputs with eachother.
    Anybody have a solution to add a extra field?

    1. Gary says:

      Did you ever get this sorted out?

  30. This is great, EXCEPT, it starts to bug out after about 13 or 14 todo's have been added. You cannot rearrange todo's below that number. I'm not sure if it's an integer issue or a screen height issue.

    I added sever todo's on your demo just to be sure is wasn't my libs, and it's buggy there too. I would love to find a solution.

    Garrett

  31. James LeRoy says:

    Awesome App! I have looked at every php todo app I can find in the past year and this one was almost everything I wanted.

    I have made several modifications similar to what others have suggested.

    I posted my updated version on sourceforge

    http://sourceforge.net/projects/surrealtodo/files/surrealtodo-0.1.zip/download

    Here's a list of the changes I've made so far:

    reduce font size
    set to save on enter and cancel on esc
    add new lists
    make lists draggable
    save list location
    allow tasks to drag between lists
    edit list name
    delete lists
    change 'new todo' button
    change Save and Cancel text to be icons
    have list container resize to fit tasks
    only show edit and delete icons on mouseover
    fix hover not showing icons on new Todo or List
    add view/hide tasks (collapsable)
    store collapsed state in db

    1. tez says:

      the code does not work :(

  32. Alex says:

    Man this is really great.
    I love it. I`ve tried to make an ASP.net and C# version last night but i got stuck. Will let you know when it is finished and i`ll put the code here. Will link it to your site as well :D

    Cheers ,
    Alex

  33. Eli says:

    how can you modify to include InnoDB and foreign keys in the todo.class.php queries?

    what i mean is how can I add WHERE id=$id AND user_id=$user_id ?

  34. Great script yet again and in depth tut.

    Would be great to have a time stamp on it and make it so that users icon link appears on the TODO.

    We would like to use this only for members within current db.
    A master delete and hide delete buttons to all but admin would be great.

  35. reni says:

    @garrett
    "it starts to bug out after about 13 or 14 todo’s have been added"

    I remove this at the script.js:
    containment : 'window',

    and now it works. i can drop without problems.

  36. James LeRoy says:

    Surreal ToDo, the list manager app inspired by this demo, is steadily progressing.

    You can see the demo here http://getsurreal.com/surrealtodo/demo

    and download the source from http://sourceforge.net/projects/surrealtodo/

    If you liked this demo, you won't be disappointed.

  37. Orlenko K.N. says:

    This is great tutorial, Thank u! =)
    I will used it in my small project

  38. ildar says:

    its unreal! its like program but better!
    i'll use this in my intrasite! - thx u!!!

  39. Daniel says:

    Hello,
    thanks for this great tutorial.
    I want to refresh the page every each seconds or better, when a todo is posted by someone.
    how can i do that without refresh the whole page?
    Thanks

  40. Rick says:

    Great tutorial!

    One little criticism however: Your code - its a little....messy. For example:

    public function __toString(){

    Its generally considered that all curly braces should be on a new line like so:

    public function __toString()
    {

    In addition the script has MAJOR security flaws. Even if it is a demo, there's no excuse for not putting in correct checking on all user input.

    1. Scott says:

      Honestly, I think it enhances readability to keep the braces with the function name. I, personally, despise the sloppy look of having each code block leaving the curlies hanging in the wind. The last time I checked, it's still considered "personal style."

      And cut some slack -- this wasn't a security demo. He was demoing the core functionality.

  41. Fantastic tutorial - Yet another inspired post, i'll be using something similar in my clients area application.

  42. Excellent tutorial! learnt a lot here!

    1. narun says:

      good and easy to understand

  43. Sebastian says:

    This is a great way of learning to build basic applications in PHP, JS and AJAX.
    Good job, thanks a lot! :-)

    1. Fahad says:

      Hello. I tried creating the program but got stuck in how to create the database. Can you please provide me the program?

  44. JoJo says:

    Thanks for the great tutorial!
    I've got into trouble when I added too much items.
    I tried to add more than 10 items into the to do list,
    For the first 9 to do items, the rearrange function works very well,
    but then begin from the 10th to do item, I cannot drag them to rearrange their position,
    Is this a limitation of the program? or How can I fix the program?
    Thanks a lot!

  45. Muse says:

    Hi, Very simple question.

    I have been trying to add a second text field and cannot seem to get it to work.

    Can someone please advise how I would go about this.

    Kind Regards,

    Muse

  46. TJ says:

    Null text should delete the todo element.

  47. ernando says:

    Is it possible to make a login form to have different todo pages for different users?

  48. Jeremy says:

    Hi,

    I have a problem, if there are more than 20 Todo item, I can't put the first element at the end of the list...

    An idea???

    Regards

  49. Jeremy says:

    I found the answer:

      $(".todoList").sortable({
    
    axis        : 'y',              // Only vertical movements allowed
    containment : 'window',         // Constrained by the window
    update      : function(){       // The function is called after the todos are rearranged
    
     
      // The toArray method returns an array with the ids of the todos
                var arr = $(".todoList").sortable('toArray');
    

    the containment value must be changed.

  50. rory says:

    I've been playing around with this list for a while. Some really useful applications for it. I was just wondering how you would add more editable elements to the list item. Ive got it displaying the time that the todo were created, but say i wanted to add a "details" field aswell. any ideas?

  51. Tim says:

    I have been trying to "conditionally color" the output entries of the list. I've done this by adding the color to the "echo $item;" statement.
    e.g. echo "<span style=\"color:blue\">$item</span>";
    I have also tried other methods like using <font color.
    This does what i want but the problem is that as soon as the color is added you can no longer move entries up & down the list. if you do, they go back to where they were on the next page refresh. something about adding the color is affecting the function that "reorders" the list.
    Does anyone here have an idea what could be causing this?
    I have also noticed that when you enable the color then try to drag an entry around it looks different now. The other entries don't "pop" out of the way like normal. you can still "reorder" them but the hole doesn't open up for you before you drop.
    fyi, i have pulled any color settings for text from the CSS file.

  52. Dav says:

    Thank for your job but i replaced private $data by protected $data and i created a setter setDBLink().

    private static $_dblink;
    public static function setDBLink($link)
    {
    self::$_dblink = $link;
    }

  53. Dex Barrett says:

    I know real users/developers don't use IE but just for you to know, the sortable behavior won't work in IE 9. The weird thing is the demo page of JQuery's website does work. I noticed they call a method called .disableSelection() after .sortable()

  54. Federico says:

    Hi,
    I love your project so I decided to extend it.
    Here you can find my version.
    http://www.itry.it/download/todo/
    I've added categories to todo items, so it is possibile to filter todo list.

  55. At the moment I use sticky notes, but may someday be shifted to an electronic version;)
    I will remember where to seek help.

  56. Lewis says:

    Amazing tutorial!

    I noticed the rearrange method under the ToDo class contains an array called $updateVals, shouldn't it be $strVals?

  57. Ronie says:

    Hey, I have a question for this one. How can I change the text:"New Todo Item. Doubleclick to Edit."

    Thanks

    1. Lewis says:

      @Ronie Under script.js Part 3 you'll see this

      $.get("ajax.php",{'action':'new','text':'New Todo Item. Doubleclick to Edit.'},function(msg){

  58. Hans says:

    AWESOME to do list, exactly what I was looking for !!!

    but, I have got a question,

    when I start to using it, it didn't work.

    What I did:

    I put every file in my xamp folder ( php and mysql is running ), and when I try to click the Add Button, nothing happens.

    Is it because I of some php problems ? WordPress is running for example, so this couldn't be the problem with php.

    Another question:

    To run it, do I just have to rename the .php in .html or how can I integrate the .php in my html code ?

    Sorry for the newbie questions but I am quiet new to that.

    1. Hans says:

      Problem Solved:

      Didn't integrated the mysql table.

      BUT, still the Question, do I just have to rename the .php to .html ?

  59. Gary says:

    Hi

    Awesome tutorial I have been going through all the files and have it up and running.

    I'm not a javascript wizz by any means but I can get around.

    What would be the easiest way to add an additional type of Todo input. I want to add a text-area as well as the option for a text-box, and to have one button to add each.

    Is there an easy way to add this in?

    Thanks

    1. Gary says:

      Ok so I have created a textarea instead of just a text box.

      Now I want to integrate tinyMCE into the textarea box for editing, nothing I try seems to work has anyone tried this?

      Advice?

  60. joy says:

    Hello~ may I ask if someone noticed the bug? :\
    When the list is not already fit(because I tried 25 to-dos) in the screen, a scrollbar on the side of the browser will appear then I'll scroll down to drag a to-do from bottom to the top of the list then the graphic bug will appear.
    The cursor is not holding already the to-do. It is like a floating to-do.

    May I ask how to fix this?? Thank you in advance :D
    anyways, thanks for sharing. Really helped me

  61. Slim says:

    It's really a great work thank you

    1. shopnopoka says:

      I have tried to use it after downloading the demo.
      When I click "add to todo" the new default todo "New Todo Item. Doubleclick to Edit." is not shown.
      However, when I click refresh the default todo is displayed.
      When I am trying to delete or edit the todo I get the AJAX effect and that todo is deleted or edite.

      What can be the reason for the AJAX effect to be absent during adding theme?

      1. Klemen says:

        I am a noob in php but I kind of resove it with adding conditional to check if id was set:

        if(isset($_GET['id']))
        $id = (int)$_GET['id']
        in ajax.php file.

        Now it works.

        Cool tutorial and thanks!

  62. Misel says:

    Hello there!
    It's a nice script I also implemented it on my page, but I've found a bug in it.
    Since I'm Hungarian, I often use letters, like ö ü ó ő ú é á ű í
    If I enter some of them to the todo, I'm not even able to save it, and when I can, on the next reload it converts to something like this: éöüóő

    Can you look after this, since I've found nothing :S

    Thanks in advance

  63. karolin says:

    Hi there,

    This looks awsome. However I would need two columns for that. How can I do this?

    Thanks for your help.

    Karolin

  64. Martin says:

    Nice!

    I used this tutorial to start the web version of my android goal manager "Goal Do+".

    I also used other tutorials from here, like this login tutorial

    Thank you very much!

  65. wiyono says:

    very nice, thank you.....

  66. Niclas says:

    Great and simple script. There are not many out there that does this in such a fancy and simple way. However, I got this weird message in Firebug console when clicking "Add a ToDo":
    NS_ERROR_XPC_BAD_CONVERT_JS: Could not convert JavaScript argument arg 0 [nsIDOMWindow.getComputedStyle]

    So I decided to try the latest jQuery 1.9.1, but the I got errors about ".live", which is deprecated since 1.7. Now you should instead use ".on". So here are the lines to replace in script.js to make it work again. First, line number, then the old line, then the new line.

    57:
    $('.todo').live('dblclick',function(){
    $('body').on('dblclick','.todo',function(){

    64:
    $('.todo a').live('click',function(e){
    $('.todo').on('click','a',function(e){

    74:
    $('.todo a.delete').live('click',function(){
    $('.todo').on('click','a.delete',function(){

    80:
    $('.todo a.edit').live('click',function(){
    $('.todo').on('click','a.edit',function(){

    110:
    $('.todo a.discardChanges').live('click',function(){
    $('.todo').on('click','a.discardChanges',function(){

    119:
    $('.todo a.saveChanges').live('click',function(){
    $('.todo').on('click','a.saveChanges',function(){

    I hope it helps someone. Now I'm gonna try and customize it to my needs. I saw there were some nice mods to in in these comments, but I had trouble finding the source, or the source had changed so much that it wasn't simple anymore.

    So thanks for this! :)

Add Comment

Add a Reply

HTML is escaped automatically. Surround code blocks with <pre></pre> for readability.
Perks:   **bold**   __italics__   [some text](http://example.com) for links