How to Create an AJAX Based Voting System

January 11, 2009 by admin  
Filed under Javascript, PHP, Tutorials

This tutorial describes how to create a voting system with stars like below. We assume you have a web server that can run php scripts, a MySQL database, and a browser with javascript enabled.


Except we're gonna take it a step further and include the code to submit the vote (via AJAX) and return the new average rating.

We need 3 graphics for this tutorial: The a lit up star, a blank star, and a loading graphic. Shown below.

Next we need some CSS to style the stars for being lit up and blank:

<style type="text/css">
.starOn{
background-image: url("/images/full-star.gif");
background-repeat: no-repeat;
width: 10px;
height: 10px;
}
.starOff{
background-image: url("/images/clear-star.gif");
background-repeat: no-repeat;
width: 10px;
height: 10px;
}
</style>

Now lets write the PHP code to display the rating stars. This code can be inserted into a PHP script where you have multiple items to rate. The $item variable must be unique. Name this file displayStars.php.

function displayRating($item)
{
echo "<div id=\"processingDiv-$item\" style=\"display:none\">\n";
?> 
<img src="ajax-loader.gif"></div>
<?php
echo "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>\n";
for ($i=1; $i<=10; $i++)
{
if ($i == 1) $class = "starOn"; else $class = "starOff";
echo "<td>\n";
echo "<div class=\"$class\" id=\"ratings-$item-$i\" onmouseout=\"javascript:HoverStars('$item', 1)\" onmouseover=\"javascript:HoverStars('$item', $i)\" onmouseup=\"javascript:SubmitVote($i, '$item')\"></div>\n";
echo "</td>\n";
}
echo "</tr></table>\n";
 
}

Notice the javascript functions for onmouseout, onmouseover, and onmouseup. onmouseout and onmouseover will handle lighting up the stars while SubmitVote() will be our javascript AJAX function to submit it to our server side script.

Here's all the javascript for lighting up the stars as well as the AJAX, put this in displayStars.php. This will send the rating, and ajaxSubmit will show the loadingDiv while the request is being sent and targetDiv will display the data returned from our vote.php script. targetDiv should be the name of the Div you want it to display in, so for example you may name them targtDiv-0, targetDiv-1 for item 0, 1, and so on.

<script type="text/javascript">
function ajaxSubmit(url, processingDiv, targetDiv)
{
targetArea = document.getElementById(targetDiv);
processingArea = document.getElementById(processingDiv);
 
var xmlHttp;
try
{ xmlHttp=new XMLHttpRequest(); }
catch (e)
{
 try
  { xmlHttp=new ActiveXObject('Msxml2.XMLHTTP'); }
   catch (e)
    {
    try
     { xmlHttp=new ActiveXObject('Microsoft.XMLHTTP'); }
    catch (e)
     {
      alert('Your browser does not support AJAX!');
      return false;
     }
   }
 }
 
xmlHttp.onreadystatechange=function()
 {
  if(xmlHttp.readyState==4)
   {
    processingArea.style.display = 'none';
    targetArea.innerHTML = xmlHttp.responseText;
   }
}
 
processingArea.style.display = 'block';
xmlHttp.open('GET',url,true);
xmlHttp.send(null);
}
 
function SubmitVote(vote, item)
{
var poststr = 'vote.php' +
'?item=' +  item + 
'&vote=' +  vote;
 
LockStars(item, vote);
ajaxSubmit(poststr, 'processingDiv-'+item, 'ratingDiv-'+item);
}
 
function HoverStars(item, star)
{
var starCount;
for (starCount=1; starCount<=star; starCount++) 
 document.getElementById('ratings-'+item+'-'+starCount.toString()).className = 'starOn';
for (starCount=star+1; starCount<=10; starCount++) 
 document.getElementById('ratings-'+item+'-'+starCount.toString()).className = 'starOff';
}
 
function LockStars(item, star)
{
var starCount;
for (starCount=1; starCount<=star; starCount++) 
{
document.getElementById('ratings-'+item+'-'+starCount.toString()).className = 'starOn';
document.getElementById('ratings-'+item+'-'+starCount.toString()).onmouseover = null;
document.getElementById('ratings-'+item+'-'+starCount.toString()).onmouseout = null;
document.getElementById('ratings-'+item+'-'+starCount.toString()).onmouseup = 'javascript:void(0);';
}
for (starCount=star+1; starCount<=10; starCount++) 
{	
document.getElementById('ratings-'+item+'-'+starCount.toString()).className = 'starOff';
document.getElementById('ratings-'+item+'-'+starCount.toString()).onmouseover = null;
document.getElementById('ratings-'+item+'-'+starCount.toString()).onmouseout = null;
document.getElementById('ratings-'+item+'-'+starCount.toString()).onmouseup = 'javascript:void(0);';
}
}
</script>

ajaxSubmit(url, processingDiv, targetDiv) submits the URL 'url' and displays the processingDiv and returns this server side script's output to targetDiv which in this case is the updated average rating.

SubmitVote(vote, item) Takes an integer 'vote' and submits it for 'item'.

HoverStars(item, star)Lights up the stars for 'item' up to 'star'. The function is called on onmouseout with star 1 to return it to it's initial value.

LockStars(item, star) Locks the stars after the vote has been submitted

The following PHP code displays the stars for 10 items. Put this in displayStars.php.

for ($item=0; $item<=10; $item++)
 displayRating($item);
function displayRating($item)
{
echo "<div id=\"processingDiv-$item\" style=\"display:none\">\n";
?>
<img src="ajax-loader.gif"></div>
<?php
echo "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>\n";
for ($i=1; $i<=10; $i++)
{
if ($i == 1) $class = "starOn"; else $class = "starOff";
echo "<td>\n";
echo "<div class=\"$class\" id=\"ratings-$item-$i\" onmouseout=\"javascript:HoverStars('$item', 1)\" ";
echo "onmouseover=\"javascript:HoverStars('$item', $i)\" onmouseup=\"javascript:SubmitVote($i, '$item')\"></div>\n";
echo "</td>\n";
}
echo "</tr></table>\n";
}

Now create a database for all the items with all the fields you need (such as the item name, description, and whatever else you need) as well as an integer 'votes' and a decimal 'votesavg'.

The following PHP code should be in a separate PHP file for handling the server side processing of the vote. For this example I named it vote.php. Make sure that the 'item' displayed in the previous file corresponds to the item's id in the database.

$dbhost = "localhost";
$dbuser = "root";
$dbpass = "yourpassword";
$db = "yourdatabase";
 
$connection = mysql_connect($dbhost, $dbuser, $dbpass);
 
if (isset($_REQUEST["item"])) $item = $_REQUEST["item"];
if (isset($_REQUEST["vote"])) $vote = $_REQUEST["vote"];
if ((is_numeric($vote)) && ($vote <= 10))
  $item = mysql_escape_string($item);
  SubmitVote($item, $vote);
}
 
function SubmitVote($item, $vote)
{
$getVoteQuery = "SELECT voteavg, votes from yourtable where id = $item";
$getVoteResult = mysql_query($getVoteQuery);
 
$currentVoteCount	= mysql_result($getVoteResult, 0, "votes");
$currentVote		= mysql_result($getVoteResult, 0, "voteavg");
 
$newVoteCount = $currentVoteCount+1;
$newVote = (($currentVote * $currentVoteCount)+$vote) / ($newVoteCount);
 
$newVote = Round($newVote, 2);
$updateVoteQuery = "UPDATE `yourtable` SET `voteavg`=$newVote, `votes`=$newVoteCount WHERE id = $item;";
$updateVoteResult = mysql_query($updateVoteQuery);
 
echo "$newVote";
}
 
mysql_close($connection);

In PHP files that serve AJAX, make sure there is no extraneous output before or after the <?php ?> tags as they will be returned in the AJAX request (unless of course you want it to be returned)

So now we have just two files our main file, displayStars.php and vote.php. When you hover your mouse over the stars, they light up and once you vote, they are locked on that rating and will not let you vote again unless you refresh.

The server side script takes the rating and returns the new average rating to display in the ratingDiv.

So lets say you have a table with a list of videos with the title, description, location, and so on you would add two extra columns, `votes` and `voteavg`. This is to keep track of how many votes there are, and what the average vote is.

You can download a working example below, just unzip the files and follow the directions in readme.txt.

AJAX Voting Example

Conclusion and further reading

AJAX is a powerful technology and an integral part of web 2.0. Keep an eye out for more AJAX tutorials.

del.icio.us Digg Facebook Google reddit SlashDot StumbleUpon Technorati