Home  >  

Sports Tournament Style Brackets with jQuery and jQuery UI (2)

Author photo
AddThis Social Bookmark Button
Last week I began a series detailing the creation of a sports tournament style brackets picker built with jQuery. As I wrapped up the previous entry, I had the basic display done, and had made use of the Selectable interaction library from jQuery UI to enable selection of winning teams in each game. However, I did not have a way to handle unique selections and I didn't have a way of noticing when you had picked all the winners. Today's entry will correct both problems. Be sure to read the earlier post (or at least the complete source of the demo) or a lot of the following won't make much sense.

First let's talk about the single selection problem. If you take a quick peek at the first demo, notice that nothing prevents from picking both teams as a winner in each game. While that would certainly make for some safe bets in Vegas, it doesn't help us get to to a final winner in the bracket. I did some digging into the Selectable docs and was not able to find a way to enable single selection. I found this listserv posting where Richard Worth suggested a much simpler way to handle single selection.

$("#myList > *").click(function() {
   $(this).toggleClass("selected").siblings().removeClass("selected");
});


So here was the old code that enabled the Selectable interaction for each game:

for(var i=0;i<round.length;i++) {
 	$("#selectable_"+i).selectable()
}


and I've now replace it with:

for(var i=0;i<round.length;i++) {
 	$("#selectable_"+i+" > li").click(function() {
  	  $(this).toggleClass("selected").siblings().removeClass("selected")
  	  checkComplete()
  	});
}


As you can see, I switched Richard's method. I've also added a checkComplete() call. This is what will handle seeing if the round is complete. Let's talk a bit about that as it was a somewhat of a pain to handle. The idea is simple enough, right? We have N games. Each game consists of two teams that where we know that at most one can be selected at a time. Our "rule" then should be simple - if each pair has one item selected, then the round is complete. I'll show the code I came up with and then discuss it a bit more in depth.

function checkComplete() {
 	//get all the games at this round
 	var round = rounds[currentRound]
 	var allGood = true
 	var winningTeams = []
 	for(var i=0;i<round.length;i++) {
  		//for each, if both aren't selected, allGood is false
  		var totalselected = $("#round_"+currentRound+" #selectable_"+i+" > li.selected").size()
  		if(totalselected != 1) {
   			allGood=false
   			break
   		} else {
   			//this is the id of selected team
   			var winningid = $("#round_"+currentRound+" #selectable_"+i+" > li.selected").attr("id")
   			//its in the form team_
   			var id = winningid.split("_")[1]
   			var winningname = $("#round_"+currentRound+" #selectable_"+i+" > li.selected").attr("innerHTML")
   			winningTeams[winningTeams.length] = {id:id,name:winningname}
   		}
  	}
 	
 	if(allGood) {
  		currentRound++
  		//first round
  		rounds[currentRound] = []
  			
  		//assign new games
  		for(i=0;i < winningTeams.length; i=i+2) {
   			var game = {}
   			game.team1 = winningTeams[i]
   			if(winningTeams[i+1] != null) game.team2 = winningTeams[i+1]
   			rounds[currentRound][rounds[currentRound].length] = game
   		}
  			
  		//draw the games
  		drawGames(currentRound)
  	
  	}
}


First, we grab a pointer to the current round. I added a variable to my code to store the current round so this is globally available. Next I set a simple boolean value, allGood, that I'll use as a flag to see if the round is done. From the previous blog entry we know that a round is an array of games. I loop over each item in the array and get a count of the number of items with the selected class:

var totalselected = $("#round_"+currentRound+" #selectable_"+i+" > li.selected").size()


This was the first time I had used the size() attribute and, honestly, the first time I had need of it. As you can guess, it simply gives you a count of the number of items matched by your selector. Each round is a UL wrapped by a div named round_X where X is a the round number. So the selector says: Within round X, game i, count the LI tags with the selected class. If the matched size is not 1 we can set allGood to false and break out of the loop.

If the matched size is 1, notice I then grab the selected item, which is the winning team, and begin to parse data about it. I store the teams ID value (which if you remember from the first entry would have come from the database) and the teams name. This gets added to a new array called winningTeams.

The last thing we do is loop over the winningTeams array and add it as a new round. Once we've created new games from the winning teams, we can call drawGames() again. The end result is that we can now pick winners until we run out of teams to pick!

Picture 4.png

You can view a demo of this here. It's definitely moving along now but we have two final problems. First, if you do indeed get to the end you will notice a JavaScript error. The code simply can't handle running out of rounds. Second, once we do get to the end, we need to serialize the results. What teams you picked and at what round. Once serialized we could send it to the server for storage. There are a few other things we should look at as well. You can continue to click teams in earlier rounds, but doing so doesn't impact the later rounds. It would be easiest probably to just remove the toggle feature once you've completed a round. We should also look at improving the UI a bit so each round is a bit more distinct.

Thoughts so far?

Read more from Raymond Camden. Raymond Camden's Atom feed cfjedimaster on Twitter

Comments

Leave a comment


Tag Cloud

Poll: Mobile Features

What feature do you use most on your mobile phone?

Vote | View Poll Results | Read Related Blog Entry

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.