Build an MSDN-style content rater with ASP.NET, MS AJAX, and jQuery
In the MSDN library, content can be rated by clicking on a star (from 1 through 5). When you hover over the content rateR on MSDN2, a textbox appears to allow comments to be added. Using the rating control and the jQuery library, we can very easily create a content rater simliar to the one on MSDN.
The first task is to set up our database table and the stored procedures. I use SQL Server 2005 but you can just as easily use the Express version or SQL Server 2000. In your database, make a new table call Item_Ratings which will have the following fields: RatingID (primary key, int), Rating (int), Comments (nvarchar 1000), ItemID (varchar),and DateAdded (datetime). The Rating ID is the primary key in our table. The ItemID is the unique ID of the product, blog entry, article, or whatever that will be rated; this value will be retrieved from the querystring. Our content page retrieves its content from the database using a querystring value since we use the querystring value for the unique ID of the content to be rated.
We will use a stored procedure called spInsertRating to add the rating to the database. Here is the stored procedure:
INSERT INTO Item_Ratings (ItemID, DateAdded, Rating, Comments, IPAddr) VALUES (@ItemID, @dateadded, @rating, @comments, @IPAddr)
Now it's time to start adding the controls to out content page. We will to need add a ScriptManager control the page. Add an update panel to the page next. This UpdatePanel will contain the Rating control, the comment textbox and the linkbutton which will submit the rating and comments into the database. Our next step is to add the Rating control from the AJAX toolkit to the content page. You will also need some star images to be displayed when the user hovers over or clicks the Rating control. The images i used were the ones from the Ajax Control Toolkit samples. Once you have copied these images into your images folder, you'll need to set some CSS rules in your style sheet as well as setting the properties on the Rating control. The CSS is below. I pretty much copied these CSS rules from the CSS file in the Ajax Toolkit samples.
.ratingStar {
font-size: 0pt;
width: 13px;
height: 12px;
margin: 0px;
padding: 0px;
cursor: pointer;
display: block;
background-repeat: no-repeat;
}
.filledRatingStar {
background-image: url(../images/FilledStar.png);
}
.emptyRatingStar {
background-image: url(../images/EmptyStar.png);
}
.savedRatingStar {
background-image: url(../images/SavedStar.png);}
The code for the Rating control should look like this.
<ajax:Rating ID="ArticleRating" runat="server"
CurrentRating="3"
MaxRating="5"
StarCssClass="ratingStar"
WaitingStarCssClass="savedRatingStar"
FilledStarCssClass="filledRatingStar"
EmptyStarCssClass="emptyRatingStar"
/>
Immediately after the Rating control add a div to hold our textbox for the comments and the linkbutton.
<div id="divComments" runat="server">
<p><strong>Comments: </strong><asp:TextBox ID="txtComments" runat="server" TextMode="MultiLine" CssClass="txtcomment" />
<asp:LinkButton ID="lnkbtnRateIt" runat="server" OnClick="RateIt">Rate It</asp:LinkButton></p>
</div>
<p> <strong><asp:Literal ID="ltrVoted" runat="server" /></strong> </p>
We will use some CSS to style the div and comment text box.
#divComments
{
border: black 1px solid;
background-color: #eeeeee;
width:300px;
height: 175px;
padding: 5px;
position: absolute;
margin-top: 15px;
}
.txtcomment
{ width: 300px;
height: 100px;
}
Now it's time for some jQuery magic. jQuery is a a JavaScript library that changes the way you write javascript. It greatly simplifies the process of traversing HTML, manipulating HTML, handling events, creating animations, and adding Ajax to your web pages. jQuery is designed to help you "find things" and "do stuff". jQuery allows you to find page elements using CSS classes or the element's ID. Also jQuery uses a special ready function which contains the jQuery code you want to run. This ready function check to see if the DOM is ready prior to your code running. By using this method, your bound function will be called the instant the DOM is ready to be read and manipulated. In the example below we attach a click event to all of the <a> tags so that when clicked, an alert appears. Instead of the a tag we could have just as easily passed in an ID for a specific link. Notice that in the click event we can pass in a function. This function is where we will do some show/hide magic. For more on jQuery check out the jQuery website which is full of documentation and code samples. You can find some examples on show/hide with jQuery here.
$(document).ready(function(){
$("a").click(function(){
alert("Thanks for visiting!");
});
});
The jQuery code for showing/hiding the comment textbox is presented below. Inside the ready function we first call the hide function so that the div is hidden once the dom is ready (just before page load). We then add a click event to the Rating control; we access the rating control's ID using ArticleRating.ClientID. In the click event's function we call the animate effect. When you click the Rating control, you will see the effect - the div expands from the top left corner and fades into view. The numeral 700 controls the speed of the animation. Next we add the hover event to the comment div. The hover takes as its first argument the onmouseover effects and takes the onmouseout effects for the second argument. This way the comment div stays open when we are typing in it and then closes when we move the cursor off the comment div.
$(document).ready(function() {
$('#divComments').hide();
$('#<%=ArticleRating.ClientID %>').click(function(){
$('#divComments').animate({ width: 'show', height: 'show', opacity: 'toggle'}, 700);
});
$('#divComments').hover(function(){
$('#divComments').animate({ width: 'show', height: 'show', opacity: 'toggle'}, 700);},
function(){
$('#divComments').animate({ width: 'hide', height: 'hide', opacity: 'toggle'}, 700);
});
});
At the end of this article you can see the end result; hover or clicking on the rating control show the comment div. The last piece of code is the code behind logic. This code inserts the rating into the database. On this site i use the Enterprise Library 3.1 so this code is written take advantage of the Enterprise Library. You should not have too much trouble converting it take advantage of your own data access library. If you any issues send us an email.
Public Sub RateIt(ByVal s As Object, ByVal e As EventArgs)
qs = Request.QueryString("articleid")
dal.RateArticle(CInt(qs), ArticleRating.CurrentRating, txtComments.Text, "")
'NEW CODE IS HERE ArticleRating.Enabled = False
lnkbtnRateArticle.Enabled = False
divComments.Visible = False
'END NEW CODE
ltrVoted.Text = "Thank you for voting."
End Sub
The code from the data access layer is below. On this site i use the Enterprise Library 3.1 so this code is written take advantage of the Enterprise Library. You should not have too much trouble converting it take advantage of your own data access library.
Public Overrides Sub RateArticles(ByVal ItemID As Integer, ByVal Rating As Integer, ByVal Comments As String)
Dim db As Database = DatabaseFactory.CreateDatabase
Dim dbCommand As System.Data.Common.DbCommand = db.GetStoredProcCommand("spInsertRating")
db.AddInParameter(dbCommand, "@id", DbType.String, ArticleID)
db.AddInParameter(DbCommand, "@Rating", DbType.Int32, Rating)
db.AddInParameter(DbCommand, "@Comments", DbType.String, Comments)
db.AddInParameter(DbCommand, "@DateAdded", DbType.DateTime, DateTime.Now)
db.AddInParameter(dbCommand, "@IPAddr", DbType.String, Context.Request.UserHostAddress)
Using connection As System.Data.Common.DbConnection = db.CreateConnection()
connection.Open()
db.ExecuteNonQuery(DbCommand)
connection.Close()
End Using
End Sub
The only item i did not cover in this article is how to allow users to vote only once. There are different ways to enforce 1 vote per user, including cookies and forcing users to login prior to voting. I'll leave it to you decide which method is best for your situation.
Update: I should also mention that I placed the Rating control, the div that holds the comment box, and linkbutton inside an UpdatePanel to eliminate the postback normally associated with clicking a linkbutton.
Update 8/18/07: I found a problem with the content rater at the bottom of the article pages. When the linkbutton is clicked to submit the rating and comments, the comment box does not hide. To fix, we need make some changes to the code. We need to add the runat=server attribute to the divComments div. Then in the code behind method RateIt we need to hide the div once the user has voted using divComments.Visible = False. Also we need to fix the jQuery code to the use the Client ID since the div will now have its changed. Use #<%=divComments.ClientID %> in place of #divComments in the jQuery code. Also we can add a literal control with ID ltrVoted right after the div and then use this literal to display a message to the user thanking them for voting.