Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>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.</p> <p>Hooking up the events is well-covered elsewhere and I won't go into it here.</p> <p>Sending the data to the server, you can use ajax. The DIY way looks roughly like this (but don't actually use this code, see below):</p> <pre><code>var xhr = new XMLHttpRequest(); xhr.open("POST", "/path/to/server/destination"); xhr.onreadystatechange = handleStateChange; xhr.send("id=" + encodeURIComponent(id) + "&amp;user=" + encodeURIComponent(userId) + "&amp;vote=up"); function handleStateChange() { if (xhr.readyState === 4) { // POST complete and we have response, check it if (xhr.responseText !== "ok") { // Or whatever you want it to be // Report problem } } } </code></pre> <p>The <code>new XMLHttpRequest</code> part of the above only works with modern browsers; for earlier versions of IE and such you have to use <code>new ActiveXObject</code> instead. <a href="http://msdn.microsoft.com/en-us/library/ms535874%28v=vs.85%29.aspx" rel="noreferrer">See examples here</a> (although I always thought that was fairly convoluted).</p> <p>That's an example of how things can vary a bit browser to browser. When doing rich web programming, there are a <em>lot</em> of these little browser differences (including hooking up event handlers!), and so I'd recommend using a good, well-supported library to smooth those over and to provide a lot of utility functionality. You have plenty to choose from: <a href="http://jquery.com" rel="noreferrer">jQuery</a>, <a href="http://prototypejs.org" rel="noreferrer">Prototype</a>, <a href="http://developer.yahoo.com/yui/" rel="noreferrer">YUI</a>, <a href="http://code.google.com/closure/library" rel="noreferrer">Closure</a>, or <a href="http://en.wikipedia.org/wiki/List_of_JavaScript_libraries" rel="noreferrer">any of several others</a>.</p> <p>Here's the above using jQuery:</p> <pre><code>$.ajax({ url: "/path/to/server/destination", type: "POST", data: {id: id, userId: userId, vote: "up"}, success: function(response) { if (response !== "ok") { // Or whatever you want it to be // Report problem } } }); </code></pre> <p>...and the other libraries will offer similar helper features.</p> <p>(Neither of those examples&nbsp;&mdash; the DIY way or the jQuery one&nbsp;&mdash; handles HTTP errors correctly, which naturally you want to do, but that gives you an idea.)</p> <hr> <p><strong>Update</strong>:</p> <p>And just for fun, here's a complete example using jQuery (but I'm not pushing jQuery; you can do something very similar, and probably just about as easy, with any of the other libraries I mentioned above; it's just easiest for me to dash off an example using jQuery, as that's the library I currently use):</p> <p>HTML:</p> <pre><code>&lt;div class="article" data-itemid="427"&gt; &lt;a href="voteup" class="vote up" &gt;Up&lt;/a&gt; &lt;a href="votedown" class="vote down"&gt;Down&lt;/a&gt; &lt;!-- ...the contents of the item... --&gt; &lt;/div&gt; </code></pre> <p>JavaScript using jQuery:</p> <pre><code>jQuery(function($) { // Hook up our vote handlers $("a.vote").live('click', voteClick); function voteClick(event) { var voteLink, voteType, item, itemId; // Regardless of the below, we handle the event, so "consume" it event.stopPropagation(); event.preventDefault(); // Get the anchor element, wrapped in a jQuery instance voteLink = $(this); // See if the vote has already been done or is in progress if (voteLink.hasClass('done') || voteLink.hasClass('inprogress')) { // Ignore the click, possibly tell the user why return; } // Get the vote type voteType = voteLink.hasClass('up') ? 'up' : 'down'; // Get the item we're voting on item = voteLink.closest('.article'); // Get its ID itemId = item.attr('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.addClass('inprogress'); $.ajax({ url: 'savevote', data: {itemId: itemId, voteType: voteType}, type: 'POST', success: votePostSuccess, error: votePostError }); // Called when the POST is successful function votePostSuccess(response) { // The POST worked voteLink.removeClass('inprogress'); // Did things work on the server? if (response === "ok") { // Or whatever // Yes, the vote was successfully recorded voteLink.addClass('done'); } else { // Report an error to the user, the server couldn't record the vote } } // Called when the POST fails for some reason (HTTP errors) function votePostError(xhr, statusText, err) { // Not in progress anymore voteLink.removeClass('inprogress'); // Report error to user } } }); </code></pre> <p>Some notes:</p> <ul> <li>All of the code above is wrapped in a function that I pass into the <code>jQuery</code> function. That tells jQuery to run the code when the DOM is "ready" (<a href="http://api.jquery.com/ready" rel="noreferrer">more</a>). Alternately, just put your <code>script</code> tag at the bottom of the <code>body</code> tag (more <a href="http://developer.yahoo.com/performance/rules.html" rel="noreferrer">here</a> and <a href="http://groups.google.com/group/closure-library-discuss/browse_thread/thread/1beecbb5d6afcb41" rel="noreferrer">here</a>).</li> <li>I've put an <code>href</code> 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 <code>href</code> 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 <code>href</code> as well.)</li> <li>I'm storing the ID of the item we're voting on in a <a href="http://www.w3.org/TR/html5/elements.html#embedding-custom-non-visible-data-with-the-data-attributes" rel="noreferrer"><code>data-</code> attribute</a>.</li> <li>We find the item to vote on by locating the "closest" article to the button that was clicked. jQuery's <code>closest</code> function starts with an element and examines that element, then its parent, then <em>its</em> parent, etc., until it finds a match for the CSS selector you pass in. So the vote buttons are associated with the article by containment; the article being voted on <em>contains</em> the voting buttons.</li> <li>I'm using POST because the call changes server state, so GET is inappropriate</li> <li>The callbacks for the ajax post are <em>closures</em> (note how they're defined <em>within</em> <code>voteClick</code> and I use <code>voteLink</code> in them, even though it's a var in <code>voteClick</code>). <a href="http://blog.niftysnippets.org/2008/02/closures-are-not-complicated.html" rel="noreferrer">Closures are not complicated</a>, but there are a couple of things it's important to know about them which I've tried to address in that linked article.</li> <li>I'm using jQuery's <a href="http://api.jquery.com/live" rel="noreferrer"><code>live</code></a> feature, which is a mechanism for doing <em>event delegation</em>. That way, I can add items to vote on to the page dynamically and not worry about hooking up handlers to their voting buttons.</li> </ul>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload