views:

102

answers:

5

I'm writing myself a little game in JavaScript, using jQuery. The game has a board, with cells in it, much like Minesweeper: the user clicks a cell, and its data needs to be changed in some way. Each cell is presented by a simple image, but has some more data associated with it.

What I mostly need is, when the user clicks a cell, I have to somehow determine the row and column which was clicked, manipulate the data appropriately and change the view.

On one hand, setting the click handler on every individual cell seems like an overkill, but if you set the click handler on the whole table, it becomes PITA to determine which table cell was clicked.

How would you handle such a situation? Maybe there is a plugin already that can simplify the whole thing?

+2  A: 

add the click handler on the whole table. use event.target to get the clicked cell. add an attribute to each cell that will tell you what row/col it is, that way you dont have to run any massive/heavy JS to figure it out.

psuedocode:

$("table.game").click(function(e){
  var cell = e.target;
  var pos = $(cell).attr("name").split["_"];
  var x = pos[0];
  var y = pos[1];
  return false;
});

markup:

<table class="game">
  <tbody>
  <tr>
   <td name="0_0">
     sdfasdfa
   <td>
  </tr>
  </tbody>
</table>

note: having a name start with a digit isnt good, so fix as needed

mkoryak
What "massive/heavy JS" are you talking about exactly? See my answer for how easy it is.
nickf
maksymko said that he have an image in each cell so the `e.target` could be the image and in this case this method won't work. nope?
p4bl0
in that case, set the name attribute of the image to be the cell coords. problem solved
mkoryak
@nickf: your answer requires parsing the dom tree. if the dom tree is big, then this will be slow. my answer requires parsing exactly one attribute per click
mkoryak
A: 

If your table is generated dynamically (js or php for instance) you could have each cell with a class and / or id attributes that gave you the information.

I don't know how you represent your cells so in pseudo code :

<table id="board">
  <row>
    <cell id="cell-0x0" />
    <cell id="cell-0x1" />
    ...
  </row>
  <row>
    <cell id="cell-1x0" />
    ...
  </row>
  ...
</table>

Then in jQuery :

$('#board cell').click(function(){
  var coord = $(this).attr('id').substr(5).split('x');
  // do your stuff
});
p4bl0
A: 

Hello,

If you have too many table cells setting the click handlers would be heavy, but you can make a workaround to calculate the box number from mouse click's event.page.X and event.page.Y this will give coordinatesof clicked pixel on your screen and you can calculate which box is under that pixel.

Or

You can also use event.target the get the node clicked.

check out jquery.event.

hope it helps, Sinan.

Sinan Y.
check out `jquery.live()`
nickf
+1 because i don't think what you said is stupid nor a bad anwser and i don't see why it has been downvoted.
p4bl0
same for you, sometimes you can't understand what folks are upto here nevermind.
Sinan Y.
it's not a good idea, because you'd have to iterate across all your table cells finding out their position and dimensions to find which one you clicked on, when there's a perfectly good function called `live()` which uses event bubbling to do this without all the kludge.
nickf
I don't want to make it yours is bad mine is good, but i think i don't have to iterate, basic math would do what is needed here. I'm aware of live() it's really good, what i'm saying is, you don't even need to use any other thing than click itself and simple math.
Sinan Y.
+1  A: 

This is a perfect example of a great use of the live() function. To find the x and y positions you just need to count the number of cells before or rows above this one:

$('#minesweeperTable td').live('click', function() {
    var $this = $(this),
        xPos = $this.prevAll('td').length,
        yPos = $this.closest('tr').prevAll('tr').length
    ;
    // your code here
});

The best thing about this is that no matter how many cells you have, there's only one event handler which makes for much better performance.

nickf
@nickf, it can be one line of code but you have to consider how much memory it allocates behind the scenes, heavyness doesn't mean how many lines that you write.
Sinan Y.
@sinan: it traverses across the nodes counting up, probably somewhere in the range of 1-30 nodes. I think your PC can handle it.
nickf
@nickf, You're right if there are 30 nodes or even 300 nodes, what if every cell is 10 by 10 pixels? if the game area is 1000x1000 then you can calculate how many nodes there will be, but a simple math function can easily calculate on which cell the click is fired because you know how big the cells are, then you can easily run whatever necessary. best. Sinan.
Sinan Y.
nickf
Here's my test results: If you had a minesweeper grid **10000** wide and clicked on the last one, it'd take about 0.12 seconds. http://jsbin.com/anodi
nickf
lets not forget the $('#minesweeperTable td') selector which may return 10000x10000 objects, which we must iterate through to assign the event handler. now do this on IE6 and it may be a different story
mkoryak
your test on IE6/1.1Ghz takes 1.49 seconds :P which is probably not acceptable
mkoryak
@mkoryak: that's not how live works. call that *before* you build the table and it's O(1). look, if you're concerned about the performance when you have *10,000 cells* and you run it on IE6 on an old computer, then fine go with the other method. This is simplest and most robust method.
nickf
Since the table I have is not big at all (30x30) I think I'll stick to your solution. Didn't know that "live" function is so cool. Thank you!
maksymko
A: 

The click event bubbles and the original target can be found in the srcElement property of the event object (I think, or it might be another property, but it's there).

erikkallen