Lately I've been working with jQuery plugins and I decided to create a tutorial demonstrating how to use the jQuery plugin system to build a simple star ratings control.
Almost all controls and features within jQuery are now built using the plugin architecture. It's actually a very simple system, and jQuery provides some pretty good documentation to get you started. Like always, let's start with an example of what we're going to build. Below I've got two star ratings controls with differing amounts of stars - one with 10 and one with 5.
Your Rating: not set
Your Rating: not set
Here's the source code required to build this example.
<head>
<link type="text/css" rel="stylesheet" href="jquery.ratings.css" />
<script src="jquery-1.3.2.min.js"></script>
<script src="jquery.ratings.js"></script>
<script src="example.js"></script>
</head>
<body>
<div id="example-1"></div> <br />
Your Rating: <span id="example-rating-1">not set</span>
<br /><br />
<div id="example-2"></div> <br />
Your Rating: <span id="example-rating-2">not set</span>
</body>
</html>
Just like any other jQuery control, all that's needed is an empty div to hold it. Here I've created two - one for the 10 star example, and one for the 5 star example. In the head of the document, we have to include all of our needed files: the CSS file that describes the look of our stars, jQuery itself, the ratings plugin, and the script that actually tells the plugin to create the controls.
Let's start with example.js.
$('#example-1').ratings(10).bind('ratingchanged', function(event, data) {
$('#example-rating-1').text(data.rating);
});
$('#example-2').ratings(5).bind('ratingchanged', function(event, data) {
$('#example-rating-2').text(data.rating);
});
});
If you've worked with any jQuery UI controls, this should look pretty familiar. We first get a jQuery object for our example div and call ratings(), which will populate the div with the ratings control. Whatever number is passed into ratings will be used to set the number of stars. You can also pass a second parameter that sets the initial rating to something other than zero. We then bind to the 'ratingchanged' event and set the contents of our "Your Rating" label to the selected rating. And that's all that's required to create the ratings controls.
Next up is the CSS. This will be pretty important if you want your ratings control to look different than mine.
width: 36px;
height: 36px;
background-image: url('empty-star.png');
background-repeat: no-repeat;
position: relative;
float: left;
margin-right: 2px;
}
.jquery-ratings-full {
background-image: url('full-star.png');
}
jquery-ratings-star is used to set the look and feel for all stars. position and float should not be changed or the stars will be put in strange places, but everything else can be tweaked to get your desired look. jquery-ratings-full is simply used to set the look of the star when it is highlighted.
All right, now down to the meat of the plugin, jquery.ratings.js. The very first thing we need to do is tell jQuery about the new function, ratings.
return this;
};
This function satisfies the bare minimum requirements for a new jQuery function. All new public functions are added to the jQuery.fn object. All new functions must return the jQuery object, unless otherwise stated. The function should also end with a semi-colon to prevent compression from breaking the code.
Unfortunately, this empty function doesn't do us any good. We need to actually start building some stuff. We'll be using the this object passed into the function in order to add our ratings control. Since this could be a selector containing more than one element, we need to iterate over it using each.
//Save the jQuery object for later use.
var elements = this;
//Go through each object in the selector and create a ratings control.
return this.each(function() {
});
};
The first thing I do is save this into a local variable. Because of some scoping issues later, this won't always refer to the jQuery object. Next up, I set up an each to loop through each element in the selector. Since each returns the jQuery object, I can simply return it from my function.
Next up we need to set up the container div that's going to hold our stars.
//Save the jQuery object for later use.
var elements = this;
//Go through each object in the selector and create a ratings control.
return this.each(function() {
//Make sure intialRating is set.
if(!initialRating)
initialRating = 0;
//Save the current element for later use.
var containerElement = this;
//grab the jQuery object for the current container div
var container = jQuery(this);
//Create an array of stars so they can be referenced again.
var starsCollection = Array();
//Save the initial rating.
containerElement.rating = initialRating;
//Set the container div's overflow to auto. This ensure it will grow to
//hold all of its children.
container.css('overflow', 'auto');
});
};
Before I do anything, I make sure initialRating is initialized to something. If the user did not pass in a value, it will be set to 0. I then save the container element and a jQuery object for the container element to variables. Next, I create an array to hold all of my star objects. I then create and set a field on the container element to hold the selected rating. Lastly, I set overflow to auto so the container div will expand to hold the child objects.
We've finally made it to the point where we can build the stars.
//Save the jQuery object for later use.
var elements = this;
//Go through each object in the selector and create a ratings control.
return this.each(function() {
//Make sure intialRating is set.
if(!initialRating)
initialRating = 0;
//Save the current element for later use.
var containerElement = this;
//grab the jQuery object for the current container div
var container = jQuery(this);
//Create an array of stars so they can be referenced again.
var starsCollection = Array();
//Save the initial rating.
containerElement.rating = initialRating;
//Set the container div's overflow to auto. This ensure it will grow to
//hold all of its children.
container.css('overflow', 'auto');
//create each star
for(var starIdx = 0; starIdx < stars; starIdx++) {
//Create a div to hold the star.
var starElement = document.createElement('div');
//Get a jQuery object for this star.
var star = jQuery(starElement);
//Store the rating that represents this star.
starElement.rating = starIdx + 1;
//Add the style.
star.addClass('jquery-ratings-star');
//Add the full css class if the star is beneath the initial rating.
if(starIdx < initialRating) {
star.addClass('jquery-ratings-full');
}
//add the star to the container
container.append(star);
starsCollection.push(star);
}
});
};
Here we have a simple loop to create stars based on the number passed in by the user. First up, I actually need an element to hold the star, so I create one using document.createElement. I then get a jQuery object from the new element. Next, I set the rating that this star represents and add the jquery-ratings-star css class. If the star is beneath the specified initial rating, I add the jquery-ratings-full class to it to make it highlighted. All that's left is to add it as a child to the container and push it into the stars array.
If you were to run the code right now, you'd see a bunch of gray stars. Let's hook up the events to actually make it work.
//Save the jQuery object for later use.
var elements = this;
//Go through each object in the selector and create a ratings control.
return this.each(function() {
//Make sure intialRating is set.
if(!initialRating)
initialRating = 0;
//Save the current element for later use.
var containerElement = this;
//grab the jQuery object for the current container div
var container = jQuery(this);
//Create an array of stars so they can be referenced again.
var starsCollection = Array();
//Save the initial rating.
containerElement.rating = initialRating;
//Set the container div's overflow to auto. This ensure it will grow to
//hold all of its children.
container.css('overflow', 'auto');
//create each star
for(var starIdx = 0; starIdx < stars; starIdx++) {
//Create a div to hold the star.
var starElement = document.createElement('div');
//Get a jQuery object for this star.
var star = jQuery(starElement);
//Store the rating that represents this star.
starElement.rating = starIdx + 1;
//Add the style.
star.addClass('jquery-ratings-star');
//Add the full css class if the star is beneath the initial rating.
if(starIdx < initialRating) {
star.addClass('jquery-ratings-full');
}
//add the star to the container
container.append(star);
starsCollection.push(star);
//hook up the click event
star.click(function() {
//set the containers rating
containerElement.rating = this.rating;
//When clicked, fire the 'ratingchanged' event handler.
//Pass the rating through as the data argument.
elements.triggerHandler("ratingchanged", {rating: this.rating});
});
star.mouseenter(function() {
//Highlight selected stars.
for(var index = 0; index < this.rating; index++) {
starsCollection[index].addClass('jquery-ratings-full');
}
//Unhighlight unselected stars.
for(var index = this.rating; index < stars; index++) {
starsCollection[index].removeClass('jquery-ratings-full');
}
});
container.mouseleave(function() {
//Highlight selected stars.
for(var index = 0; index < containerElement.rating; index++) {
starsCollection[index].addClass('jquery-ratings-full');
}
//Unhighlight unselected stars.
for(var index = containerElement.rating; index < stars ; index++) {
starsCollection[index].removeClass('jquery-ratings-full');
}
});
}
});
};
This is actually the complete code. We've now added all the events that are required to add interactivity to the ratings control. The first event is hooked to each star's click. Whenever a star is clicked, the container's rating is updated and the 'ratingchanged' event is triggered. The next event, mouseenter, makes sure the correct stars are highlighted. Whenever a star is moused over, all stars beneath is are highlighted and all stars greater than it are unhighlighted. The last event is hooked to the container. This event makes sure the correct number of stars are highlighted when the user's mouse leaves the control. The highlighted stars should revert back to the last selected state when the mouse leaves. This is done similar to the star's mouse enter event. Every star beneath the current rating is highlighted and every star above the current rating is unhighlighted.
And that's it. Now we've got a working jQuery plugin for star ratings. If you've comments, questions, or suggested feature additions to this control, leave them below or in the forums.
05/19/2009 - 12:01
This has to be the easiest to use star rating jQuery plugin I have seen so far. Thanks!
06/12/2009 - 07:48
Hey Brandon, did you know you could have created a div like so:
$('<div></div>'). And you can actually add attributes and whatnot as well.06/12/2009 - 09:03
My guess is createElement is faster since it doesn't need to parse the HTML before creating the DOM object, however I don't know for sure.
07/11/2009 - 08:11
Hey Guys,
I need some specific sort of rating system for my website. Before I go discussing project details (which is based on this article but will require extra coding), needed to ask you if you accept custom project requests. Pricing can be set, I won't mind paying what you ask for.
skype adymate1.
Regards,
Andy.
07/11/2009 - 08:12
And Yahoo - netproint at yahoo dot com
Andy.
07/11/2009 - 09:24
Andy, go ahead and send us an email through our contact us link, we would be happy to at least discuss the possibility.
08/13/2009 - 23:58
Hi guys,
I have tried to implement the star within the jQuery tab..however it stopped working..I can't even see the stars..But the stars work fine if I placed them outside the tab...
Tab that I am using is this plugin
http://stilbuero.de/jquery/tabs/
I've been tried to solve this issue for a week now...but I can't find any resources or solution...
Please help me on this issue..
Thank you so much.
10/08/2009 - 03:58
hi,
simple and easy to use plugin, good work!
but i had one problem when i used it like this:
jQuery(this).find("input").val(data.rating);
});
it created all 4 ratings with full functionality and bind the ratingchanged to all 4, but it was changing only first one input.
so i rewrite it to get it worked:
jQuery(this).ratings(10).bind('ratingchanged', function(event, data) {
jQuery(this).find("input").val(data.rating);
});
});
is here any option to rewrite plugin to get it done with first piece of code or is there some mistake in my first code?
thnaks for reply,
steve
12/22/2009 - 05:31
How to read the rated stars??
01/13/2010 - 21:40
nice collect it to
http://ajax.wespai.com
01/18/2010 - 12:21
I will try this and provide feed back
03/19/2010 - 07:15
I was looking for an accessible way to get started with jQuery and this tutorial was perfect - thanks!
06/01/2010 - 15:03
where should I paste the formating code and the jQuery.fn.ratings function? Inside of head or body?
Thanks a lot!!!
08/23/2010 - 16:15
Extremely useful tutorial! I slightly modified it to
star.click(function() {
//When clicked, fire the 'ratingchanged' event handler. Pass the rating through as the data argument.
if (containerElement.rating == this.rating) {
elements.triggerHandler("ratingchanged", {rating: 0});
containerElement.rating = 0;
} else {
elements.triggerHandler("ratingchanged", {rating: this.rating});
containerElement.rating = this.rating;
}
});
this way allowing to 'unset' rating by clicking on the same star
09/03/2010 - 10:16
How to read the rated stars?
09/03/2010 - 10:28
I understand. Thank you!
11/03/2011 - 08:54
i just wanted to save that rating value to an variable please help me on this ..................
02/15/2011 - 10:33
many thanks for your article :)
but sorry, but how to read the stars after all? lets say we have a form and a hidden input field, how to update its value after user clicks the stars?
thank u in advance!
02/15/2011 - 11:50
In the first javascript snippet, I bind to the ratingchanged event. Right now, the handler just updates the text of the field containing the selected rating. This would be a good place to update the value of the input field.
11/14/2011 - 09:12
Could you please give an example?
04/15/2011 - 14:46
Is Possible to simple modify this peace of code frome the first .js file to put the rating value into a .net lable?
$(document).ready(function() {
$('#example1').ratings(10).bind('ratingchanged', function(event, data) {
$('#examplerating1').text(data.rating);
});
05/31/2011 - 10:33
Hey,
I have uploaded the rating to my database to create an overall rating. How do I grab that rating from the database and convert the data to stars?
05/31/2011 - 10:56
The number of stars to display is passed in through the plugin.
06/02/2011 - 17:11
Super helpful plugin, thank you!
I'm working on a page with 50 or so star ratings so I'd really rather not write a function for each.
I'm able to convert selecting over to a class rather than div easily and that gets the rating bars to work. However, I can't reference the results individually nor can I pre-set individual ratings with this approach. I am using a class on the element and id to separate the items.
var id = $(this).attr("id");
$("input[name='" + id + "']").val(data.rating);
});
The goal is to show 50 rating bars. Have each control a corresponding form field and pre-populate from a database record.
Any suggestions?
06/02/2011 - 17:21
Looks like I should have tried more before posting.
The code to accomplish this is:
$(this).ratings(10).bind('ratingchanged', function(event, data) {
var id = $(this).attr("id");
alert('this div is' + id);
$("input[name='" + id + "']").val(data.rating);
});
});
I am still working on how to pre-set the individual ratings.
06/02/2011 - 17:26
All solved. One silly ; had me all mixed up. Thank you for a great plugin!
06/10/2011 - 06:07
How to set individual (starting) stars?
06/14/2011 - 13:40
thank you for the plug in, right now im trying to put in a comment when a star is selected, example: when you select 1 star comment=worst, instead of a 1, and so on with each star, can you help me please
07/26/2011 - 18:04
hola Amigos de switchthecode..perdón por la molestia pero estoy trabajando con un sitio donde necesito implementar el sistema de votación mediante estrellas y ya me funciona pero tengo una consulta....ah, perdón, alguien habla español?
09/28/2011 - 05:38
How do I store the ratings and associate it with each user in the database? I am using cakephp structure (MVC). I want to record each user ratings and store it in the user database in the column rating. Each user can vote any times, and the value will be updated only.
10/10/2011 - 18:38
Nice work! Modded it a bit and added Bohdan's addition for easy resetting to make it perfect.
You did a great job... and it took ages for me to find it on Google. ;)
12/27/2011 - 23:11
but how do i insert the result on a Database?:
01/09/2012 - 02:06
I am also looking for the same thing as you Lucas, anyone can help?
Add Comment
[language] [/language]
Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]
See here for supported languages.
Javascript must be enabled to submit anonymous comments - or you can login.