Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement up and down voting? [closed]

If you have used Stack Overflow for a while, you surely have used the function of vote up and down of the question and answer. I notice Stack Overflow uses <a> anchor. But I don't know how to POST the data to server. I think it's JavaScript associated with this <a>, but I can't find it. How can I implement it?

like image 981
Magic Avatar asked Jun 09 '11 06:06

Magic


People also ask

What are 3 methods of voting?

The regular methods of voting in such bodies are a voice vote, a rising vote, and a show of hands. Additional forms of voting include a recorded vote and balloting. The assembly could decide on the voting method by adopting a motion on it. Different legislatures may have their voting methods.

How do I set up voting buttons in Outlook?

Add voting buttons Create an email message or reply to or forward a message that you received. On the Options tab, in the Tracking group, click Use Voting Buttons. Use when you need an authorization for an action.


3 Answers

Yes, JavaScript is involved. There are two parts: Hooking up a handler for the click events on the voting "buttons", and sending data to the server.

Hooking up the events is well-covered elsewhere and I won't go into it here. (For instance, I cover it in this answer.)

Sending the data to the server, you can use ajax. On any browser that isn't completely obsolete, you can use XMLHttpRequest:

var xhr = new XMLHttpRequest();
xhr.open("POST", "/path/to/server/destination");
xhr.onreadystatechange = handleStateChange;
xhr.send("id=" + encodeURIComponent(id) +
         "&user=" + encodeURIComponent(userId) +
         "&vote=up");
function handleStateChange() {
    if (xhr.readyState === 4) {
        // POST complete
        if (xhr.status === 200) {
            // POST complete and we have response, check it
            if (xhr.responseText !== "ok") { // Or whatever you want it to be
                // Report problem
            }
        } else {
            // Ajax failed, handle/report problem
        }
    }
}

On more up-to-date browsers you can use fetch:

var body = new FormData();
body.append("id", id);
body.append("user", userId);
body.append("vote", "up");
fetch("/path/to/server/destination", {
    method: "POST",
    body: body
})
.then(function(res) {
    if (!res.ok) {
        throw new Error("HTTP error " + res.status);
    }
    return res.text(); // or `res.json()` if you return JSON
})
.then(function(data) {
    if (data !== "ok") { // Or whatever
        // Report problem
    }
})
.catch(function(error) {
    // Ajax failed, handle/report problem
});

Just for fun, here's a complete example:

HTML:

<div class="article" data-itemid="427">
<a href="voteup"   class="vote up"  >Up</a>
<a href="votedown" class="vote down">Down</a>
<!-- ...the contents of the item... -->
</div>

JavaScript:

document.addEventListener("click", function(event) {
    // Regardless of the below, we handle the event, so "consume" it
    event.stopPropagation();
    event.preventDefault();

    // Get the anchor element
    var voteLink = event.target.closest("a.vote");
    if (!voteLink) {
        // Didn't find one, bail
        return;
    }

    // See if the vote has already been done or is in progress
    if (voteLink.classList.contains("done") || voteLink.classList.contains("inprogress")) {
        // Ignore the click, possibly tell the user why
        return;
    }

    // Get the vote type
    var voteType = voteLink.classList.contains("up") ? "up" : "down";

    // Get the item we"re voting on
    var item = voteLink.closest(".article");

    // Get its ID
    var itemId = item.getAttribute("data-itemid");

    // If we didn"t get an ID...
    if (!itemId) {
        // ...report error
        return;
    }

    // Mark "in progress" and initiate the vote; action continues
    // in our callbacks below
    voteLink.classList.add("inprogress");
    var body = new FormData();
    body.append("itemId", itemId);
    body.append("voteType", voteType);
    fetch("savevote", {
        method: "POST",
        body:   body
    })
    .then(function(res) {
        if (!res.ok) {
            throw new Error("HTTP error " + res.status);
        }
        return res.text(); // or `res.json()` if you return JSON
    })
    .then(function(data) {
        if (data === "ok") { // Or whatever
            voteLink.classList.add("done");
        } else {
            // Report an error to the user, the server couldn"t record the vote
        }
    })
    .catch(function(error) {
        // Ajax failed, handle/report problem
    })
    .finally(function() {
        // Not in progress anymore
        voteLink.classList.remove("inprogress");
    });
});

Some notes:

  • The code above is written in ES5 but you could use ES2015+ features in most modern browsers (or by transpiling with tools like Babel).
  • I've put an href on the links (which StackOverflow doesn't have), so that if JavaScript is disabled, we can fall back to going to a page where we let the user vote using a form submission or something. Also, links with href are treated specially by browsers (tab targets, etc.), so this is useful for accessibility. (To really do that, I'd probably have to put the article ID in the href as well.)
  • I'm storing the ID of the item we're voting on in a data- attribute.
  • We find the item to vote on by locating the "closest" article to the button that was clicked. The DOM's closest function starts with the element and examines that element to see if it fits the given CSS selector, then if not looks at its parent, then its parent, etc., until it finds a match. So the vote buttons are associated with the article by containment; the article being voted on contains the voting buttons.
  • If you were rooting the event handler in an element deeper in the page (rather than the document level), you'd probably follow the closest check with a contains check to ensure that the element the handler is attached to contains the element that was found (in case it was found in an ancestor element instead). That would be !voteLink || !this.contains(voteLink) above (instead of just !voteLink).
  • I'm using POST because the call changes server state, so GET is inappropriate
like image 181
T.J. Crowder Avatar answered Oct 28 '22 18:10

T.J. Crowder


Check out Ajax.

like image 24
Emil Vikström Avatar answered Oct 28 '22 17:10

Emil Vikström


You can use jquery to do it. Just apply click eventlisteners on the up/down arrow which will send the data to your server using ajax.

The script on your server will validate the incoming data and update count in the DB. Then you can send a response back giving the updated count of ups/downs

Note : You'll also have to take into account that a user can only like or dislike once. You can either handle it at server side / or for simplicity store it in cookie.

like image 25
Ravish Avatar answered Oct 28 '22 17:10

Ravish