ajb
ajb

Reputation: 31689

Why does $(this) work differently depending on how callback is created?

I'm trying to display a table and cause certain actions to take place if the user clicks on a cell in the table. My Javascript (using jquery-3.1.1.min) looks like this:

    $(function() { 

      function tdHeader(key) {
          return '<td class="mytable-cell" data-key="' + key + '">';
      }

      function clickHandler() {
          alert("Key: " + $(this).data("key"));
      }

      function displayTable() {
          var tabHTML = '<table class="mmmtab">';
          tabHTML += '<tr><th>Data1</th><th>Data2</th><th>Data3</th></tr>';
          for (var i = 0; i < 3; i++) {
              tabHTML += '<tr>';
              for (var j = 0; j < 3; j++) {
                 key = i + "-" + j;
                 tabHTML += tdHeader(key) + ((i + 1) * (j + 1)) + '</td>';
              }
              tabHTML += '</tr>';
          }
          tabHTML += '</table>';
          $("#mytable").html(tabHTML);
          $(".mytable-cell").click(clickHandler);                 // Version 1
//        $(".mytable-cell").click(function() {clickHandler();}); // Version 2
      }

      displayTable();
    });

What I'm finding is that if I use Version 1 to set up the callback, then if I click on a cell, the alert box displays the correct key. However, if I use Version 2, the alert box says "Key: undefined".

What's going on, and why does it make a difference which callback I use?

[Assuming I need the Version 2 because I want to pass some local data to the handler, I can solve my problem by passing $(this).data("key") as a parameter to the handler. But I'd still like to know why it's doing this.]

Upvotes: 1

Views: 65

Answers (2)

t.niese
t.niese

Reputation: 40842

jQuery calls the callback you pass to click in the context of the element the event belongs to. So for $(".mytable-cell").click(clickHandler); the clickHandler is called in the context of the given DOM element.

For $(".mytable-cell").click(function() {clickHandler();}); the anonymous function is called in the context of the DOM element and inside of this you call clickHandler in the context of undefined or the global object.

You would need to write $(".mytable-cell").click(function() { return clickHandler.apply(this, arguments); } ); if you want that the behavior is the same.

Upvotes: 4

jiajianrong
jiajianrong

Reputation: 928

jQuery .on will change 'this' automatically for your event callback. In version 1, 'this' in clickHandler will be $(".mytable-cell"). But in version 2, 'this' is window. (Because your event callback calls clickHandler, clickHandler makes a new context)

please try:

$(".mytable-cell").click(function() {clickHandler.bind(this)();});

Upvotes: 2

Related Questions