29

I am trying to make a tictactoe project in jQuery and I am having a major problem...

The tiles are in <td> tags and I am trying to make it so that when the user clicks the the tile, it calls the "marked" function.

If we now look into the "marked" function, $(this) is intended to be the <td> node that the function was called from.

However, it wasn't doing anything so I checked the console and apparently $(this) was containing the DOM Window object.

Is there anyway I can send the right kind of $(this) to the "marked" function?

Thank you!

<script type="text/javascript">

    var TURN_X = false;
    var TURN_O = true;

    var turn = false;  // this is to see whos turn it is.

    $(document).ready(function(){

        var listCells = $.makeArray($("td"));
        $("td").click(function(){marked(listCells)});   //THIS IS WHERE I HAVE PROBLEMS
        return false;
    });

    function marked(arr)
    {
        console.log($(this));  // THIS CONSOLE LOG RETURNS "DOM Window"
        $(this).addClass("marked");

        if(turn == TURN_X)
        {
        this.innerHTML = "X";
        turn = false;
        }
        else
        this.innerHTML = "O";

        var tileNum = $(this).attr("id");
    }
James Wiseman
  • 29,946
  • 17
  • 95
  • 158
wayfare
  • 699
  • 2
  • 9
  • 17
  • 1
    Do you want to pass in the entire array (i.e. `listCells`) or just the table cell you clicked on? - If just the td you clicked on you could use `$("td").click(function(){marked($(this))});` in your click event.. – Greg Mar 05 '12 at 08:24

8 Answers8

30

You code does not follow the right principles.

$(function(){
    var TURN_X = "X",
        TURN_O = "O", 
        turn   = TURN_O,
        $listCells = $("td");

    function marked() {        // define event handler
        var $this   = $(this),
            tileNum = $this.attr("id");

        if ( !($this.hasClass("marked") ) {
            $this.addClass("marked").text(turn);
            turn = (turn == TURN_X) ? TURN_O : TURN_X;
        }
    }

    $listCells.click(marked);  // attach event handler
});
  1. Wrap everything in the document.ready function. Avoid global variables wherever possible.
  2. Make use of the fact that jQuery manages this for you. this will always be what you expect if you pass callback functions directly instead of calling them yourself.
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • 1
    This is just a side question but I was just curious why wrapping everything in the ready function and avoiding global variables are good coding habit. – wayfare Mar 06 '12 at 01:39
  • Also, I am trying to create an array of "td" tags present. From my understanding, the selector operation $("td") returns nodeList, not array. Will assigning $("td") to a jquery object $listCells convert the nodelist into an array? – wayfare Mar 06 '12 at 01:41
  • 2
    @wayfare **a)** Polluting the global namespace has side effects, most prominently variables from different parts of a project that overwrite each other. As long as a project is small, this does not happen. When a project grows, this can introduce annoying and hard-to-find bugs. Apart from that it is bad style to transport state through global variables. **b)** A jQuery object *is* an array. No need to convert it. `$('td')` returns an array of `` nodes. Note that I use `$varname` to denote a variable that contains a jQuery object - it's a convention. – Tomalak Mar 06 '12 at 06:01
15

Send the element which fire the event to the function like that:

$("td").click(function(){
        marked($(this));
        return false;
    });

and in the function:

function marked(td)
{
     console.log($(td));  
     $(td).addClass("marked");
     //....
}
Hounshell
  • 5,321
  • 4
  • 34
  • 51
Hadas
  • 10,188
  • 1
  • 22
  • 31
4

More simply, use bind :

$(".detailsbox").click(function(evt){
   test.bind($(this))();
});
function test()
{
   var $this = $(this);
}
Daphoque
  • 4,421
  • 1
  • 20
  • 31
1

Try:

$("td").click(function(event){
    marked(listCells, $(this));
});

Then:

function marked(arr, sel) {
    console.log($(this));
    sel.addClass("marked");

    if(turn == TURN_X) {
        this.innerHTML = "X";
        turn = false;
    } else {
        this.innerHTML = "O";
    }
    var tileNum = $(this).attr("id");
}
francisco.preller
  • 6,559
  • 4
  • 28
  • 39
0

try this:

$(function(){
    var listCells = $.makeArray($("td"));
    $("td").click(function(){marked($(this),listCells)});  
});



function marked(o,arr)
{
...
quzary
  • 285
  • 1
  • 4
0

You can use the call method to specify the scope for the function:

$("td").click(function(){ marked.call(this, listCells); });

Now the marked function can access the clicked element using the this keyword.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
0

You need to pass $(this) to your function:

$("td").click(function(){ marked(listCells, $(this))} );

And modify your function like this:

function marked(arr, that)
{
  that.addClass("marked");

  if(turn == TURN_X)
  {
    that.innerHTML = "X";
    turn = false;
  }
  else
    that.innerHTML = "O";

  var tileNum = that.attr("id");
}
Sarfraz
  • 377,238
  • 77
  • 533
  • 578
0
$(document).ready(function(){
    var TURN_X = false,
        TURN_O = true,
        turn = false,
        listCells = $.makeArray($("td"));

    $("td").click(function() {
        marked(listCells, this)
    });

    function marked(arr, self) {
        $(self).addClass("marked");

        if(turn == TURN_X) {
            self.innerHTML = "X";
            turn = false;
        }else{
            self.innerHTML = "O";
            var tileNum = self.id;
        }
    }
});
adeneo
  • 312,895
  • 29
  • 395
  • 388