Friday, November 14, 2008

dynamic rating system

Social applications are more and more popular. Users want to feel they are not alone using the application. A good way to achieve this is to give them the possibility to rate an article. Rating something shouldn't be a long process. Users don't expect to have a complete page reload for such a small action. The solution is to use AJAX to send the user's rating and to retrieve the average rating. jQuery will be used to handle events, send AJAX requests, and display rating choices and results.

You can try a working example of my dynamic rating system.

1.
Add the rating choices (I decided to use the stars images found in the /i/ of APEX). You'll probably want to add this "controller" at the top or the bottom of the content you want the users to rate.

<div id="rating">
Please rate: <img id="rating_choices" src="/i/stars5.gif" usemap="#map_rating_choices" />
</div>
<map id="map_rating_choices" name="map_rating_choices">
<area coords="6,0,15.8,12" value="1"/>
<area coords="15.9,0,25.7,12" value="2"/>
<area coords="25.8,0,35.6,12" value="3"/>
<area coords="35.7,0,45.5,12" value="4"/>
<area coords="45.6,0,58,12" value="5"/>
</map>


2.
Add the jQuery code to handle the mouse over and the mouse click events.

<script src="http://www.google.com/jsapi"></script>
<script>
// Load jQuery
google.load("jquery", "1.2.6");
</script>
<script>
$(function() {
//apply mouseover handlers
$("#map_rating_choices area").mouseover(function(e){
e.preventDefault();
$("#rating_choices").attr("src","/i/stars"+$(this).attr("value")+".gif");
});

//apply click handlers
$("#map_rating_choices area").click(function(e){
// stop normal link click
e.preventDefault();

// send request
$.ajax({
type: "POST",
url: "wwv_flow.show",
data: {p_arg_names:"P2_RATING",
p_arg_values:$(this).attr("value"),
p_flow_id:$('#pFlowId').attr("value"),
p_flow_step_id:$('#pFlowStepId').attr("value"),
p_instance:$('#pInstance').attr("value"),
p_request:"APPLICATION_PROCESS=NEW_RATING"
},
dataType: "json",
success: function(data, textStatus){
$("#rating").html(
"Thanks for rating, current average: " +
'<img src="/i/stars'+data[0].average+'.gif" alt="'+data[0].average+'" />'+
", number of votes: " +
data[0].count
);
}
});
});
});
</script>


3.
Create an application process to insert the new rating in the database. The same process will return the results using JSON.

DECLARE
l_rating NUMBER := to_number(:P2_RATING);
l_retval VARCHAR2(32767);
l_average NUMBER;
l_count NUMBER;
BEGIN
INSERT INTO JQ_RATINGS(rating) VALUES(l_rating);
COMMIT;

SELECT round(avg(rating))
,count(*)
INTO l_average
,l_count
FROM jq_ratings;

l_retval := '[{''average'':'''||l_average||''',''count'':'''||l_count||'''}]';

htp.prn(l_retval);
EXCEPTION
WHEN others THEN
htp.prn('');
END;



Have fun building your own dynamic rating system!

2 comments:

Anthony Rayner said...

Nice post and welcome to the APEX blogging world. I've added a link to your blog from mine.

Anthony.

Louis-Guillaume Carrier-Bédard said...

Anthony,
Thanks for your support.
I appreciate it.

Louis-Guillaume