Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you make a vote-up-down button like in Stackoverflow?

Problems

  1. how to make an Ajax buttons (upward and downward arrows) such that the number can increase or decrease
  2. how to save the action af an user to an variable NumberOfVotesOfQuestionID

I am not sure whether I should use database or not for the variable. However, I know that there is an easier way too to save the number of votes.

How can you solve those problems?

[edit]

The server-side programming language is Python.

like image 661
Léo Léopold Hertz 준영 Avatar asked Apr 05 '09 16:04

Léo Léopold Hertz 준영


2 Answers

This is a dirty/untested theoretical implementation using jQuery/Django.

We're going to assume the voting up and down is for questions/answers like on this site, but that can obviously be adjusted to your real life use case.

The template

<div id="answer_595" class="answer">   <img src="vote_up.png" class="vote up">   <div class="score">0</div>   <img src="vote_down.png" class="vote down">   Blah blah blah this is my answer. </div>  <div id="answer_596" class="answer">   <img src="vote_up.png" class="vote up">   <div class="score">0</div>   <img src="vote_down.png" class="vote down">   Blah blah blah this is my other answer. </div> 

Javascript

$(function() {     $('div.answer img.vote').click(function() {         var id = $(this).parents('div.answer').attr('id').split('_')[1];         var vote_type = $(this).hasClass('up') ? 'up' : 'down';         if($(this).hasClass('selected')) {             $.post('/vote/', {id: id, type: vote_type}, function(json) {                 if(json.success == 'success') {                     $('#answer_' + id)                      .find('img.' + vote_type);                      .attr('src', 'vote_' + vote_type + '_selected.png')                      .addClass('selected');                     $('div.score', '#answer_' + id).html(json.score);                 }             });         } else {             $.post('/remove_vote/', {id: id, type: vote_type}, function(json) {                 if(json.success == 'success') {                     $('#answer_' + id)                      .find('img.' + vote_type);                      .attr('src', 'vote_' + vote_type + '.png')                      .removeClass('selected');                     $('div.score', '#answer_' + id).html(json.score);                 }             });                         }     }); }); 

Django views

def vote(request):     if request.method == 'POST':         try:             answer = Answer.objects.get(pk=request.POST['id'])         except Answer.DoesNotExist:             return HttpResponse("{'success': 'false'}")          try:             vote = Vote.objects.get(answer=answer, user=request.user)         except Vote.DoesNotExist:             pass         else:             return HttpResponse("{'success': 'false'}")          if request.POST['type'] == 'up':             answer.score = answer.score + 1         else:             answer.score = answer.score - 1          answer.save()          Vote.objects.create(answer=answer,                             user=request.user,                             type=request.POST['type'])          return HttpResponse("{'success':'true', 'score':" + answer.score + "}")     else:         raise Http404('What are you doing here?')  def remove_vote(request):     if request.method == 'POST':         try:             answer = Answer.objects.get(pk=request.POST['id'])         except Answer.DoesNotExist:             return HttpResponse("{'success': 'false'}")          try:             vote = Vote.objects.get(answer=answer, user=request.user)         except Vote.DoesNotExist:             return HttpResponse("{'success': 'false'}")         else:             vote.delete()          if request.POST['type'] == 'up':             answer.score = answer.score - 1         else:             answer.score = answer.score + 1          answer.save()          return HttpResponse("{'success':'true', 'score':" + answer.score + "}")     else:         raise Http404('What are you doing here?') 

Yikes. When I started answering this question I didn't mean to write this much but I got carried away a little bit. You're still missing an initial request to get all the votes when the page is first loaded and such, but I'll leave that as an exercise to the reader. Anyhow, if you are in fact using Django and are interested in a more tested/real implemention of the Stackoverflow voting, I suggest you check out the source code for cnprog.com, a Chinese clone of Stackoverflow written in Python/Django. They released their code and it is pretty decent.

like image 132
Paolo Bergantino Avatar answered Sep 22 '22 02:09

Paolo Bergantino


A couple of points no one has mentioned:

  • You don't want to use GET when changing the state of your database. Otherwise I could put an image on my site with src="http://stackoverflow.com/question_555/vote/up/answer_3/".
  • You also need csrf (Cross Site Request Forgery) protection
  • You must record who makes each vote to avoid people voting more than once for a particular question. Whether this is by IP address or userid.
like image 31
Tom Viner Avatar answered Sep 21 '22 02:09

Tom Viner