How to Make an Upvote/Downvote Button

How can I make an Upvote/Downvote button?

You could do it by adding a different picture to the background, one for every state of the button. There is however a cleaner, easier, more modern way of achieving this result: Sprites.

A sprite is an image that is saved as a part of a larger image. One of the biggest advantages of using sprites is the reduction of round-trips to the server for all the images to just one request for the Sprites. The element to display a picture has the image as background. The background is moved relative to the element so the element displays only part of the image. Like when you move a photo-frame over a poster (or in this case: moving the poster under the frame)

At SO they make an image that contains all the states for the button. They give the element for the button (a span in this case) a fixed width and height and add the background to it with CSS. Then toggle a class for the state (on or off) with javascript on the click event. Now the only thing you have to do in CSS is change the position of the background with CSS classes:

The up/down sprite image

for (const btn of document.querySelectorAll('.vote')) {
btn.addEventListener('click', event => {
event.currentTarget.classList.toggle('on');
});
}
.vote {
display: inline-block;
overflow: hidden;
width: 40px;
height: 25px;
cursor: pointer;
background: url('http://i.stack.imgur.com/iqN2k.png');
background-position: 0 -25px;
}

.vote.on {
background-position: 0 2px;
}
Click to vote (using sprites): <span class="sprite vote"> </span>

How to make my upvote/downvote button store cookies and count votes only 1 time

You can learn HTML5 Web Storage, and use them with the following code.

$(document).ready(function() {
if(localStorage.getItem("count") == null)
$("#count").text(0);
else
$("#count").text(localStorage.getItem("count"));
});

var counter = 0;
$("#plus").click(function(){
counter++;
$("#count").text(counter);
localStorage.setItem("count", counter);
});

$("#minus").click(function(){
counter--;
$("#count").text(counter);
localStorage.setItem("count", counter);
});

How to create upvote/downvote component in React?

Your first attempt could be just to guard the individual buttons based on the state of the count like this:

render() {
return (
<div>
{this.state.count < 1 && <button onClick={this.increment}>
+
</button>}
<span>{this.state.count}</span>
{this.state.count > -1 && <button onClick={this.decrement}>
-
</button>}
</div>
);
}

Of course, if your count ends up being dependent on other users voting as well, you might want to get more sophisticated and add the ability to track the current user's vote rather than the overall vote count.

How do I code an upvote bar that stores the information and displays it?

I'm not sure if you are trying to loop through buttons. If you have more than one upvote button then you would use the for loop and it would look something like the following:

const buttons = document.querySelectorAll('.vote');

for(let i = 0; i < buttons.length; i++){

buttons[i].addEventListener('click', function() {

buttons[i].classList.toggle('active');

});

}
.vote.active{

border: 1px solid red;

}
<button class="vote">Vote</button>

<button class="vote">Vote</button>

<button class="vote">Vote</button>

Upvote and Downvote with Backbone, Express and Mongoose

There're many things that can be improved:

First, you client-side code is a low hanging fruit for an attacker - you do an atomic operation (upvote/downvote) with two requests, and the first request not only sends vote type but also sends total number of votes:

this.set ({votetype : 1 }, {votes : this.get('votes') + 1});
this.save();
// btw this looks broken, the second argument for `set` is options, so
// if you want to set votes, you should move them to the first argument:
this.set ({votetype : 1, votes : this.get('votes') + 1});

But, how your application will respond if the attacker will send 100 or even 1000 votes?
This operation should be atomic, and you should increment votes on the server when you make POST request to the /upvote endpoint.

Second, you don't really need to store votetype on the post itself - whenever user votes, you change the votetype which is visible for all users but you later hide it with the loop and it just strange to store a votetype of the last vote on the post where you clearly need to have a votetype of the particular user, therefore, you don't need it in the schema and can remote it.
You can remove votetype from the posts and you can remove the loop by storing votes history on the post itself, so whenever you want to display a post or a list of posts, you can easily filter the array to contain just the vote of the given user, so you schema will look like this:

var postSchema = new Schema({
name: String,
votesCount: Number,
votes: [{ user_id : mongoose.Schema.Types.ObjectId , type: Number }],
postedBy: { type: String, ref: 'User' },
});

And then you can get a post and filter votes with something like:

Post.findOne({_id:<post-id>)}, function(err, post){
post.vote = post.votes.filter(function(vote){
return vote.user_id === req.body.userID;
})[0].type;
res.send(post)
}
)
// or list of posts
Post.find(function(err, posts){
posts.forEach(function(post){
post.vote = post.votes.filter(function(vote){
return vote.user_id === req.body.userID;
})[0].type;
});
res.send(posts)
}
)
// you can move vote finding logic in a function:
function findVote(post) {
var vote = post.votes.filter(function(vote){
return vote.user_id === req.body.userID;
})[0]
if(vote) return vote.type;
}

If you need to display latest voted posts in the user profile you can filter posts voted by the user:

Post.find({'votes.user_id': req.body.userID}, function(err, posts){
posts.forEach(function(post){
// using findVote defined above
post.vote = findVote(post);
});
res.send(posts)
}
)

Template code on the client side should remain almost the same.

Only 1 upvote/downvote button are working

You have given both buttons the same id while the id of each element must be unique.

You can use a class to bind the click event and find the respective span and count the votes and show count of votes in that span.

Also you have only one counter. I am not sure but I think if there are two separate buttons there should be two counters, too.

$(".buttonup").click(function() {
var vote = checkIfUserVoted() != votePlus ? votePlus : counter;
localStorage.setItem("voted", vote);
$(this).next().text(vote);
});

Here is downvote button code

$(".buttondw").on('click', function () {
var vote = checkIfUserVoted() != voteMinus ? voteMinus : counter;
localStorage.setItem("voted", vote);
$(this).prev().text(vote);
});


Related Topics



Leave a reply



Submit