1

So im running into a bit of confusion on "this" in event handlers and properly preserving them. I have done a good bit of googling and have figured out "Why" this is changing when calling an element......but not really a way to fix it for my situation.

I've set up a sample concept here: https://jsfiddle.net/msmith1114/xu4zbppz/8/

You've got two buttons and a simple class. The main part im concerned about is setting up the jquery event handlers for these buttons in my class prototype (I've posted a separate question about where event handlers should "usually" go when referring to javascript classes here: ES6 Classes/Object oriented and Event Handlers)

and one of the answers does go into a little detail on "this" and it makes sense.

Just looking at the class:

class Player {
  constructor() {
    $(".demo").click(function() {
      console.log(this)
      console.log($(this).text())
    });
    this.color
    this.name = 'Player 1'
  }

  printName(player) {
    if (player == 1)
      console.log(this.name + "'s color is " + this.color)
  }
}

ER, how can I set an event handler for constructor items on clicks. IE what if I want to store the this.color (for the player class) equal to the button.text() value? If I bind $(this) then I can't refer to the button text....however if I don't bind it, I can't really store it since I can't really say in the event handler this.color = $(this).text() as great as it would be if that worked.

Or is this just straight up bad practice? Im just starting this classes and really diving into Object Oriented javascript...and I learned a lot about this and object creation, but when it came to implementing it into DOM related JS code I didn't really know where to put my event handlers. (Such as in a tic-tac-toe game, i've created a "board" class so it seems to me the event handlers would be in the "board" class itself....am I going about this the wrong way?

Or is there a workaround that makes sense. I've seen some examples that assign the click event handler to variables....but im not sure I understand the point of that (they were mostly non-jquery code anyways).

Community
  • 1
  • 1
msmith1114
  • 2,717
  • 3
  • 33
  • 84
  • What is `this.color` in the constructor supposed to do? – Barmar Apr 29 '17 at 09:09
  • Nothing this is literally just a sample I threw together it wasn't super well thought out ha – msmith1114 Apr 29 '17 at 15:01
  • Although I do not think this exactly the same as the duplicate because I understand how to switch between `this` as the object and `this` as the button that's clicked. But now how to correctly be able to use both items. – msmith1114 Apr 29 '17 at 15:27
  • The answer at the other question says: **2. Store reference to context/this inside another variable**. So you use another variable for the object, while `this` in the callback is the button that's clicked. – Barmar Apr 29 '17 at 15:30
  • @Barmar Fair enough, the question was a few years old so I didn't know if there was maybe "new" ways ha. – msmith1114 Apr 29 '17 at 15:35
  • The question is old, but the first answer is only 8 months old. – Barmar Apr 29 '17 at 15:36

2 Answers2

3

You don't necessarily have to use this in your jQuery event handler to get the element that triggered the event, you can also get it using event.target.

I would recommend you use that together with an arrow function to get the desired effect:

class Player {
    constructor() {
        this.name = 'Player 1'
        $(".demo").click(ev => {
            console.log(ev.target)
            console.log($(ev.target).text())
            console.log(this.name)
        });
    }
}

If you do not want to use arrow functions for some reason, a commonly used workaround is to assign this to a variable, e.g. _this, for reference in callbacks that have a different this scope:

class Player {
    constructor() {
        this.name = 'Player 1'
        const _this = this;
        $(".demo").click(function (ev) {
            console.log(ev.target)
            console.log($(ev.target).text())
            console.log(_this.name)
        });
    }
}

…or you can use bind:

class Player {
    constructor() {
        this.name = 'Player 1'
        $(".demo").click(function (ev) {
            console.log(ev.target)
            console.log($(ev.target).text())
            console.log(this.name)
        }.bind(this));
    }
}
Patrick Hund
  • 19,163
  • 11
  • 66
  • 95
0

I think I found the bug .. try it!

constructor(){
    $(".demo").click(function() {
        console.log(this)
            console.log($(this).text())
    });
    this.color
    this.name = 'Player 1'
}

The problem was caused by the BIND function.

Pinguto
  • 416
  • 3
  • 17