dave
dave

Reputation: 7867

Implementing an upvote/downvote system in Javascript but can't get the math right

var $arrow       = $(this);
var $sibling     = $arrow.siblings('span.arrow');
var $score       = $arrow.siblings('span.score');

var vote         = $arrow.hasClass('up') ? 'up' : 'down';
var alreadyVoted = $sibling.hasClass('voted');

if (!USER_LOGGED_IN)
{
    alert('You must be logged into vote');
}
else if (!$arrow.hasClass('voted'))
{
    if (alreadyVoted)
        $sibling.removeClass('voted');

    $arrow.addClass('voted');
    $score[0].innerHTML = parseInt($score[0].innerHTML) + ((vote == 'up') ? 1 : -1);
}

I have an upvote and downvote button. A 'current score' is shown next to these buttons which I would like to increment/decrement when a vote is cast.

For example, if they load the page and see the score is 200. When they upvote, the score will change to 201. When they downvote, the score needs to change to 199. Why? Because if they downvote after upvotting (change their mind) then the vote needs to go from the original score. Not the new score they created by upvotting.

Basically, if they upvote and then downvote, the score, currently, goes back to the original score. Their vote isn't cast.

I'm having trouble making this work so their vote is cast...

Upvotes: 5

Views: 2237

Answers (3)

T.J. Crowder
T.J. Crowder

Reputation: 1075367

It sounds like if the user has already voted up (so vote = 1) and then they click the down arrow instead, you want vote = -1 instead of vote = 0 (much as StackOverflow does it). If so, you'll need to explicitly detect that condition in your script, something like:

var voteValue = parseInt($score[0].innerHTML, 10);
if (alreadyVoted) {
    $sibling.removeClass('voted');
    // Undo the previous vote
    voteValue += $sibling.hasClass('up') ? -1 : 1;
}

// Apply the new vote
$arrow.addClass('voted');
voteValue += (vote == 'up') ? 1 : -1;
$score[0].innerHTML = voteValue;

Or, of course, if it really is either "up" or "down" (like SO), it gets a lot simpler:

if (alreadyVoted)
    $sibling.removeClass('voted');

$arrow.addClass('voted');
$score[0].innerHTML = vote == 'up' ? 1 : -1;

...since there's really no need for adding/subtracting at all.

Upvotes: 0

Stephen
Stephen

Reputation: 18964

change this bit:

parseInt($score[0].innerHTML) + ((vote == 'up') ? 1 : -1);

to this:

parseInt($score[0].innerHTML) + ((vote == 'up') ? 1 : -1) + ((alreadyVoted) ? ((vote == 'up') ? 1 : -1) : 0);

Its verbose, but it will work in a pinch.

Upvotes: 3

Robusto
Robusto

Reputation: 31903

As far as I can tell, this is working as expected. If you upvote, that's +1. If you then downvote (decrement) it's minus one, and the result of n + 1 - 1 should be n. They should have to downvote again if they want to achieve a true downvote.

Upvotes: 0

Related Questions