« Previous entry | Next entry » Browse > Snippets

Skip to comments (40) AJAX ToDo List
Posted by Erik on Feb 10 2006 @ 13:41  :: 14591 unique visits

Here is the code for my simple AJAX ToDo List, you can use this code to implement a similar todo list on your own website.

Example usage

Hopefully the code contains enough comments to understand what it does.

The Javascript


CODE: JAVASCRIPT
// the list element
var list = document.getElementById('list');

// seperator between the actual list and the add link
var sep  = list.appendChild(document.createElement('br'));

// the add link
var add           = list.appendChild(document.createElement('li'));
    add.innerHTML = '<a href="#" onclick="return false">click here to add a new item</a>';
    add.value     = '99';


// from: http://www.codepost.org/view/59
function createXMLHttpRequest() {
  var types = [
    'Microsoft.XMLHTTP',
    'MSXML2.XMLHTTP.5.0',
    'MSXML2.XMLHTTP.4.0',
    'MSXML2.XMLHTTP.3.0',
    'MSXML2.XMLHTTP'
   ];

  for (var i = 0; i < types.length; i++) {
    try {
      return new ActiveXObject(types[i]);
    } catch(e) {}
  }

  try {
    return new XMLHttpRequest();
  } catch(e) { }

  return false; // XMLHttpRequest not supported
}


// this function will be called when the add link is pressed
// and when loading the list at startup
function addnote(id, text) {
  var item = list.insertBefore(document.createElement('li'), sep);

  // span containing the html
  var html = item.appendChild(document.createElement('span'));

  // input for editing
  var edit           = item.appendChild(document.createElement('input'));
      edit.type      = 'text';
      edit.value     = text;
      edit.maxLength = 100;
      edit.size      = 100;
 
  // image for the delete button
  var dele               = item.appendChild(document.createElement('img'));
      dele.src           = 'dele.gif';
      dele.style.display = edit.style.display = 'none';

  // new note?
  if (id == -1) {
    // use an xmlhttprequest to get a new id for the note
    var req = createXMLHttpRequest();
    req.onreadystatechange = function() {
      if (req.readyState == 4) {
        if (req.status == 200) {
          item.id = req.responseText;
        }
      }
    };
    req.open('GET', 'todolist.php?getid=1', true);
    req.send('');
  } else {
    item.id = id;
  }


  item.onclick = function() {
    // switch the note to edit mode
    html.style.display = 'none';
    dele.style.display = edit.style.display = 'inline';

    edit.focus();
  };


  edit.onblur = function() {
    var t = edit.value;
        t = t.replace(/!(.+)!/g, '<i>$1</i>');   // replace !...! by italic text
        t = t.replace(/\*(.+)\*/g, '<b>$1</b>'); // replace *..* by bold text

    // has the contents of the note changed?
    if (html.innerHTML != t) {
      // use an xmlhttprequest to update the note contents in the database
      var req = createXMLHttpRequest();
          req.open('POST', 'todolist.php', true);
          req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
          req.send('id=' + item.id + '&text=' + escape(edit.value));
   }

   html.innerHTML = t;
 
   // switch the note to display mode
   html.style.display = 'inline';
   dele.style.display = edit.style.display = 'none';
  }

  // catch the enter key to finish editing the note
  edit.onkeydown = function(e) {
    var key = 0;
    if (window.event) {
      key = window.event.keyCode;
    } else if (e) {
      key = e.keyCode; // e.which
    }

    if (key == 13) { // 13 is the enter key
      edit.onblur();
    }
  }


  dele.onmousedown = function() {
    // ask the user if he/she really wants to delete the note
    if (confirm('are you sure?')) {
      // use an xmlhttprequest to remove the note from the database
      var req = createXMLHttpRequest();
          req.open('GET', 'todolist.php?del='+item.id, true);
          req.send('');

      list.removeChild(item);
    }
  }
 
  // trigger onblur to switch the note to display mode and update it's innerHTML
  edit.onblur();
}


add.onclick = function() {
  // -1 indicates a new note
  addnote(-1, 'click *here* to edit');
}


The PHP


CODE: PHP
<?

// connect to the mysql database
@mysql_connect('serveraddress', 'username', 'password') or die();
mysql_select_db('todolist') or die();


// don't allow browsers to cache the contents of this page because it may change
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache'); // for HTTP/1.0
header('Expires: Thu, 01 Jan 1970 00:00:00 GMT');


// request for a new id
if (isset($_GET['getid'])) {
  // insert a new empty note and return it's id
  if (@mysql_query('INSERT INTO notes (text) VALUES("")')) {
    echo mysql_insert_id();
  } else {
    echo 0; // the insert somehow failed (should add more error handling)
  }
}

// init the list with all current notes
else if (isset($_GET['init'])) {
  // first do a cleanup of the notes list (remove notes which are added but not edited)
  @mysql_query('DELETE FROM notes WHERE text = ""');
 
  $query = '
    SELECT id, text
    FROM notes
   '
;
  $result = @mysql_query($query);

  @header('Content-type: text/javascript');
 
  while ($row = mysql_fetch_assoc($result)) {
    $text = addslashes($row['text']);
   
    // we are returning javascript code which will call the addnote function
    echo "addnote({$row['id']}, '$text'); \n";
  }
}

// delete a note
else if (isset($_GET['del']) &&
         is_numeric($_GET['del'])) {
  @mysql_query('DELETE FROM notes WHERE id = '.$_GET['del']);
}

// update the contents of a note
else if (isset($_POST['id']) &&
         is_numeric($_POST['id'])) {
  // strip the tags from the note text
  $text = strip_tags($_POST['text']);
 
  $query = "
    UPDATE notes
    SET text = '$text'
    WHERE id = {$_POST['id']}
   "
;
  @mysql_query($query);
}

?>


The Layout of the MySQL table


CODE: SQL
CREATE TABLE notes (
  id   int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  text varchar(100)     NOT NULL DEFAULT '',
  PRIMARY KEY  (id)
);



The HTML


CODE: HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
    <link rel="stylesheet" href="todolist.css" type="text/css" />
    <title>AJAX ToDo List</title>
  </head>
  <body>
    <div class="notelist">
      <ol id="list">
      </ol>
    </div>

    <span class="info">!italic! will show as <i>italic</i></span><br />
    <span class="info">*bold* will show as <strong>bold</strong></span>

    <script type="text/javascript" src="todolist.js"></script>
    <script type="text/javascript" src="todolist.php?init=1"></script>
  </body>
</html>


The stylesheet


CODE: CSS
.info {
  font-size: small;
}

.notelist {
  _padding-top: 10px; /* for IE only */
  width: 700px;
  border: 1px #000 dotted;
}

40 comments posted so far
Add your own »

1. On Feb 10 2006 @ 13:49 guest wrote:

Awesome!! :D

2. On Feb 26 2006 @ 12:45 guest wrote:

Nice

3. On Feb 27 2006 @ 02:48 guest wrote:

AJAX strikes again!

4. On Mar 02 2006 @ 07:32 Gabriel wrote:

This is way cool.  How do you get it to save?

5. On Mar 02 2006 @ 18:00 Mario wrote:

@ Gabriel

For saving you need that "The Layout of the MySQL table" part.

I'd like to ask something the developer.

I've got it all up and running, but that DB bit is giving me the headache. It fails to save an entry permanently (gets deeted after page reload)

I make tables through phpMySQL interface, and I made this (as instructed, I guess):

CODE: OTHER
CREATE TABLE `notes` (
`id` INT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT ,
`text` VARCHAR( 100 ) NOT NULL ,
PRIMARY KEY ( `id` )
) TYPE = MYISAM CHARACTER SET latin1 COLLATE latin1_swedish_ci


But it fails to save the entry. What could go wrong?

In

CODE: OTHER
@mysql_connect('serveraddress', 'username', 'password') or die();


of .php file as serveraddsess I wrote 'localhost' and as user 'mario_nuc1' (I also modified user's permissions). I chose that username as I already use it (with success) in my base for MovableType blogging app.

Please give me some hints :)

6. On Mar 04 2006 @ 11:46 Erik wrote:

Mario try removing the @'s before the mysql statements. This way they will produce warnings if something goes wrong.
Also use this code to display errors:
CODE: PHP
mysql_connect('serveraddress', 'username', 'password') or die(mysql_error());
mysql_select_db('todolist') or die(mysql_error());

And modifie the javascript code to show you the errors (the response of the xmlhttprequests):
CODE: JAVASCRIPT
req.send('id=' + item.id + '&text=' + escape(edit.value))// search for this line
req.req.onreadystatechange = function() {
  if (req.readyState == 4) {
    if (req.status == 200) {
      alert(req.responseText);
    }
  }
};

7. On Mar 10 2006 @ 14:55 ner0tic wrote:

on line 28 it cleans out the db upon load. comment that line out and you will retain your data.

CODE: PHP
// first do a cleanup of the notes list (remove notes which are added but not edited)
  @mysql_query('DELETE FROM '.$table.' WHERE text = ""');

8. On Mar 10 2006 @ 14:58 ner0tic wrote:

scratch that i didn't test before commenting. it still doesn't get retained.not sure why though.

9. On Mar 20 2006 @ 22:43 guest wrote:

There is a bug when trying to add, for example, two bold words:

*this* is a *test*

shows as

this*is a *test

10. On Apr 10 2006 @ 01:23 guest wrote:

test

11. On Apr 10 2006 @ 09:15 mange wrote:

He, this is cool :o)
CODE: ASP
response.write "I like this to do list!"

12. On Apr 13 2006 @ 09:51 Ryan_Ryan wrote:

What if I wanted to add another input box.  For instance, say i had both the "text" column and a "content" column in my db.  What would i need to do to add this extra column to the JS/PHP?

Best,
Ryan

13. On Apr 20 2006 @ 00:32 Oliver wrote:

I tried to get this working, and I found that the is_numeric checks in the php were failing.  I got rid of them and it works fine now.

14. On Apr 26 2006 @ 18:09 komielan wrote:

The update query is failing if the note contains an apostrophe.
Replace with:
CODE: PHP
$query = 'UPDATE notes SET text = "' . $text . '" WHERE id = '. $_POST['id'];

15. On Jun 03 2006 @ 17:14 Kuni_in_Japan wrote:

I can't display x button under text boxes, so I can't delete the to-do list.

@mysql_connect('localhost', 'myID', 'myPASSWORD') or die();

Somthing is wrong?

16. On Jun 09 2006 @ 15:28 lpanebr wrote:

Solving the *bug* of multiple *bold* or !italic! words:

You just need to add the Lazzy Operator + to the * like shown below:

CODE: JAVASCRIPT
t = t.replace(/!(.+?)!/g, '<em>$1</em>');   // replace !...! by italic text
t = t.replace(/\*(.+?)\*/g, '<strong>$1</strong>'); // replace *..* by bold text
 


cheers!

17. On Jun 09 2006 @ 15:35 lpanebr wrote:

What cool additional formating like <ul> lists?

Add the lines shown below to the  "edit.onblur = function()" function of the .js file:

CODE: JAVASCRIPT
t = t.replace(/--/g, '<li>'); // replace -- by <li>
t = t.replace(/__/g, '<ul>'); // replace __ by <ul>
t = t.replace(/_/g, '</ul>'); // replace _ by </ul>
 


And remenber to add:

CODE: HTML
<span class="info">-- will be replaced by <li></span><br />
<span class="info">__ will be replaced by <ul></span><br />
<span class="info">_ will be replaced by </ul></span><br />


To the .html file so you will remember how to use it..

:-)

18. On Jun 09 2006 @ 15:42 lpanebr wrote:

Sorry.. Correcting the my post #17 above:

Where you read:
"...add the Lazzy Operator + to the * operator like..."

You should read:
"...add the Lazzy Operator ? to the + operator like..."

19. On Jul 08 2007 @ 19:05 guest wrote:

anyone got this working without using mysql and just using a text file? i would love to use it with a twiki installation, would be great, but its nice to be able to copy twiki installs easily without having to worry about mysql

anyone tried converting the script to run with a text file instead of the db?

adam

20. On Jul 13 2007 @ 01:22 guest wrote:

I set it up and made the appropriate changes to the db line where it connects. And it doesn't save the data. As soon as I try reloading it's empty again.

Very promising, but judging from other posts it doesnt seem to work in full.
Nice ajax UI, but w/o being able to save it's useless.

21. On Jul 16 2007 @ 20:27 Mcvee wrote:

What if I wanted to add another input box.  For instance, say i had both the "text" column and a "content" column in my db.  What would i need to do to add this extra column to the JS/PHP?

Best,
Ryan
I

've been trying to do just this but no luck. Please Anyone?

22. On Jul 17 2007 @ 06:35 guest wrote:

hi,

i have seen some comments saying the scripts don't work..i found they worked very well...make sure that:
1. you have the right database named. this means that when you create a db you should ensure it is called 'todolist' or change this line:
mysql_select_db('todolist') or die();

so, the process to follow for creating the db is thus (from the command line in linux - i think it works just as well in DOS):
--first connect to the db--
>mysql -u [user] -p

--then create the db--
mysql>create database todolist;

--then create the notes table--
mysql>connect todolist;
mysql>create tables notes ( id   int(10) UNSIGNED NOT NULL AUTO_INCREMENT, text varchar(100)     NOT NULL DEFAULT '', PRIMARY KEY  (id) );



2. you will have to download this image :
http://labs.mininova.org/todolist2/dele.gif

put it in the same dir as the page with the javascript (perhaps also make the link in the javascrpt to 'dele.gif' and absolute url.

if u want to see it in action  have implemented it at:
http://en.flossmanuals.net/bin/view/PureData/

adam

23. On Jul 17 2007 @ 06:40 guest wrote:

further to the note above...make sure you have php and mysql all integrated and working properly. If php cannot connect with mysql then you will not see any errors unless you make the changes that were suggested earlier in this forum.

also, I wrote the other note about getting this script to work with static files and not a db...anyone know how this could be done?

adam

24. On Jul 21 2007 @ 16:06 guest wrote:

Hello, nice script.
Is it possible to remove '99.' before "add a new note"?

25. On Jul 21 2007 @ 16:36 guest wrote:

Or better: How can I completely remove all the numbers?

26. On Jul 21 2007 @ 18:06 guest wrote:

Ouch.. as it seems, adding new fields (for instance for username) is very complicated :p

27. On Jul 24 2007 @ 20:37 guest wrote:

To remove the numbers, just change the list tag in the html file from <ol> to <ul>.

28. On Sep 05 2007 @ 07:20 Chris wrote:

I've added some additional functionality within the js file (basically a checkbox) - it can be seen at [url]http://cjhess.com/todo2/[/url]

The js file is [url]http://cjhess.com/todo2/todolist.js[/url]

Enjoy!

Chris

29. On Sep 05 2007 @ 07:29 Chris wrote:

Dang... Here are those links again... I added \...

http://cjhess.com/todo2/
http://cjhess.com/todo2/todolist.js

Guess its time for bed...

30. On Sep 10 2007 @ 17:09 EvinDesign wrote:

Thanks for a great working tutorial..very useful

But as a alternative way...
How can I use a dropdown menu with this script, instead of the "click here to add new post", I want to have a dropdown menu that fetches its content from a Mysql DB.. I have made all the arragenments but I cant get the menu to fetch from mysql nor to insert tasks to the toDo list...

Any suggestions?

31. On Oct 25 2007 @ 21:47 guest wrote:

test

32. On Nov 16 2007 @ 23:04 Darrin wrote:

How difficult would it be to change to a PostgreSQL database?

33. On Dec 16 2007 @ 12:49 timm wrote:

Nice script!!!

I only have problems using special characters like äöü or ß. It doesn't seem to be an encoding problem, because setting all collations to latin1 did not fix it. Any ideas?

34. On Jan 06 2008 @ 08:42 Scott wrote:

Chris I like your modification, but I tried cutting and pasting your javascript into my version and it just killed my to do list.

All I could see was the first item on the list :(

Did you make any changes to the php?

35. On Jan 18 2008 @ 08:15 Chris wrote:

Scott - and any others that went to the site - I realized I didn't have all the files there to make it work correctly - I now have a zip file linked on the site if you go back there - Sorry for the inconvenience!

--Chris

36. On Jan 21 2008 @ 19:29 Lukas wrote:

Hey All,

I'm trying to implement this list on my Wordpress blog but am also having trouble getting it to save to the db.

Something that seems strange to me is the way the php is being called - as a javascript - is this the right way of doing it?

I'm trying to debug it and have noticed that if I try to
echo "something";
in the php it doesn't actually get printed. I believe this has to do with the way the php is sourced (because when I do an include it works ok)
How can I debut this php sourced as a javascript?

37. On Jan 28 2008 @ 22:29 Chris wrote:

It calls the php file using javascript in the background so that the page doesn't need to reload.  It uses the php file to save the information to the database.  If you need to debug the php file you can call it directly passing in the appropriate information to make sure that it interacts with the database correctly.

38. On Feb 18 2008 @ 21:58 lukas wrote:

Ok, I figured it out. The todo list works fine but takes a few tweaks depending on where you have it installed on your blog / website. Also the debugging problem stems from the fact that the php is called as javascript and the result of todolist.php needs to be well formed javasript (or html) - using php symantics like print() won't work.

I have explained some of this here.

Very handy!

39. On Mar 28 2008 @ 18:52 j03 wrote:

Very, Very Nice. I'm gonna expand on this, so the user has their own personal todo list, and whatnot. Nice Work!

40. On Jun 24 2008 @ 16:10 dabromeit wrote:

RE: 14. On Apr 26 2006 @ 18:09 komielan
don't think your solution will change anything,
the right way is "mysql_real_escape_string()"


RE: 33. On Dec 16 2007 @ 12:49 timm
i remember the files were utf-8 encoded (not that shure anymore) ...
try to look for that and have a look in your phpmyadmin
whats the encoding of your database AND the fields


NEW:
Thx so much for this source.
I made some small changes
(priorities/sorting,
ok.jpg add if done,
255 chars instead of 100,
add-link is list external,
error if js is off,
localisation- / db- / table- variables on top of the php,
you do not have to delete default "click here" txt before writing,
blablablaaa .. just crap -.- )

i would put the source online somewhere ... but there is one huge error inside
and its in the old versions, too:
i want to use this with a friend of mine. each time i add/change something and she visits the page, its gone.
(so the whole version of today 11pm is set to the correct version of 6pm)
one of my suggestion is that if the page is loaded each node activates an event from the js-source.
the second suggestion is of course that the page is cached in her browser or something.
but the nocache headers everywhere are fine!? we're using firefox3 and ff2,latest version.
HELP please!!

Add a new comment

Name:
Password: (leave empty for anonymous comment)
 
View formatting tags Comment: