Building A Ratings Widget With ASP.NET MVC And jQuery

Posted by: Malcolm Sheridan , on 1/3/2010, in Category ASP.NET MVC
Views: 43426
Abstract: The following article demonstrates how to build a ratings widget for your website using ASP.NET MVC and jQuery.
Building A Ratings Widget With ASP.NET MVC And jQuery
 
Rating systems are all over the web today. They’re an easy and convenient way to give your users the ability to rate what their reading on the page. In ASP.NET WebForms you can use the Ajax Control Toolkit to add a ratings system to your site, but if you’re using ASP.NET MVC, this won’t work. I thought it would be good to show you one possible way of doing this with ASP.NET MVC and jQuery. The example I’m demonstrating in this article is using the new jQuery 1.4 Alpha 2 release. You can download the jQuery library from here. The end result will look like the one shown in the video below.
[YOUTUBE VIDEO]


 

 
To demonstrate this I’ve created an ASP.NET MVC application. The script to add this functionality to your site is very small, so let’s jump straight into it. The basic concept is a web page has a series of stars on a page. The user can hover their mouse over each star. By doing this the star will be highlighted. Whatever star they click on is the rating they want to give the content they’re rating. Here’s the code below:
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
    <script language="javascript" type="text/javascript" src="../../Scripts/jquery-1.4a2.js"></script>
    <script language="javascript" type="text/javascript">
        $(function() {
            $("img").mouseover(function() {
                giveRating($(this), "FilledStar.png");
                $(this).css("cursor", "pointer");
            });
 
            $("img").mouseout(function() {
                giveRating($(this), "EmptyStar.png");
            });
 
            $("img").click(function() {
                $("img").unbind("mouseout mouseover click");
 
                // call ajax methods to update database
                var url = "/Rating/PostRating?rating=" + parseInt($(this).attr("id"));
                $.post(url, null, function(data) {
                    $("#result").text(data);
                });
            });
        });
 
        function giveRating(img, image) {           
            img.attr("src", "/Content/Images/" + image)
               .prevAll("img").attr("src", "/Content/Images/" + image);
        }
    </script>       
    <p>
        <img src="../../Content/Images/EmptyStar.png" alt="Star Rating" align="middle" id="1" />
        <img src="../../Content/Images/EmptyStar.png" alt="Star Rating" align="middle" id="2" />
        <img src="../../Content/Images/EmptyStar.png" alt="Star Rating" align="middle" id="3" />
        <img src="../../Content/Images/EmptyStar.png" alt="Star Rating" align="middle" id="4" />
        <img src="../../Content/Images/EmptyStar.png" alt="Star Rating" align="middle" id="5" />
    </p>
    <div id="result"></div>
</asp:Content>
To create the rollover effect, I’ve created an event handler for the mouseover and mousreout events which calls the giveRating function. These pass the name of an image to display when these events are fired:
$("img").mouseover(function() {
giveRating($(this), "FilledStar.png");
      $(this).css("cursor", "pointer");
});
 
$("img").mouseout(function() {
giveRating($(this), "EmptyStar.png");
});
The giveRating function handles all the magic in regards to selecting all stars up to and including the current star the user is hovering over. 
function giveRating(img, image) {           
img.attr("src", "/Content/Images/" + image)
            .prevAll("img").attr("src", "/Content/Images/" + image);
}
This prevAll method finds all sibling <img> elements in front of the current <img> element and changes their image:
.prevAll("img").attr("src", "/Content/Images/" + image)
When the user is ready they can click on any star and the result will be posted to the backend using jQuery’s post method. 
$("img").click(function() {
$("img").unbind("mouseout mouseover click");
 
      // call ajax methods to update database
      var url = "/Rating/PostRating?rating=" + parseInt($(this).attr("id"));
      $.post(url, null, function(data) {
            $("#result").text(data);
});
});
 
Notice how I’m calling unbind in the code above? 
 
$("img").unbind("mouseout mouseover click");
To ensure the rating only happens once, I’m using jQuery’s unbind method remove the mouseover, mouseout and click events. Then I post the selected rating to the Rating/PostRating action method. The action method returns some JSON stating how many stars the user rated this:
 
Ratings
 
This is a nice and easy way to add more richness to your application through jQuery. The entire source code of this article can be downloaded over here
Give a +1 to this article if you think it was well written. Thanks!
Recommended Articles
Malcolm Sheridan is a Microsoft awarded MVP in ASP.NET, a Telerik Insider and a regular presenter at conferences and user groups throughout Australia and New Zealand. Being an ASP.NET guy, his focus is on web technologies and has been for the past 10 years. He loves working with ASP.NET MVC these days and also loves getting his hands dirty with jQuery and JavaScript. He also writes technical articles on ASP.NET for SitePoint and other various websites. Follow him on twitter @malcolmsheridan


Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by Ryan Smith on Monday, January 4, 2010 12:17 AM
Thanks for the article and the viedo.
Comment posted by Malcolm Sheridan on Monday, January 4, 2010 12:33 AM
@Ryan
Thanks for the feedback.  I'm trying to add a video to most of my articles to help people understand what I am trying to do.
Comment posted by Khalid Abuhakmeh on Tuesday, January 5, 2010 9:54 AM
Cool post! you could use css sprites instead of images. It gives you more options with css and can help reduce the amount of requests per rating widget.
Comment posted by Malcolm Sheridan on Tuesday, January 5, 2010 8:39 PM
@Khalid
Yes that would be a better option come to think of it.  Maybe I'll write an update using css sprites and post it soon :)
Comment posted by Jeoff Balte on Wednesday, January 6, 2010 8:48 PM
Wow this is my next task in a project I am doing and I already have it done :)
Comment posted by A-Dubb on Friday, March 26, 2010 10:10 AM
@Khalid
You're right. Could just change the background positon of the images for the rollover affect.
Comment posted by Vassil on Saturday, January 8, 2011 6:22 AM
@Malcolm
When I try to have a couple of those ratings for different items on the page it won't work. I guess because of the $("img"). I have put the script inside a foreach loop. Do you know a good way to be able to have a couple of "instances" of this rating control?
Thanks
Comment posted by Bob on Monday, March 5, 2012 1:06 PM
How can I display the current ratings?
Comment posted by Bob on Monday, March 5, 2012 1:58 PM
How can I display the current ratings?
Comment posted by Roman on Thursday, October 25, 2012 4:02 AM
Bob, Look into controller ;) You need save rating for displaing it later.

To Malcolm Sheridan:
Thanks for example)
Comment posted by Ved on Monday, December 31, 2012 3:03 PM
Hi,

Great article , thanks for putting this up. Quick question, I too have similar issue as Vassil. I am using this control as a partial control and putting it inside a for each loop. Everything works fine but if I click on 1 control..everything gets disabled. How do I solve this ? How do I change the code so that unbind only happens for selected image and not all ?
Comment posted by Ved on Monday, December 31, 2012 3:39 PM
Hi,

Great article , thanks for putting this up. Quick question, I too have similar issue as Vassil. I am using this control as a partial control and putting it inside a for each loop. Everything works fine but if I click on 1 control..everything gets disabled. How do I solve this ? How do I change the code so that unbind only happens for selected image and not all ?
Comment posted by Dave on Wednesday, February 13, 2013 3:59 PM
I was able to use the control inside a foreach by putting the following in the .click handler
var $radio = $(this);
$(this).off('mouseleave mouseenter click');
(rest of the code.....)

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel