0

Coming from a C++ background, trying to work with an OO language that doesn't have explicit typing is a little more than a headache.

So I have dynamic elements for a webpage that are "controlled" by objects since there are tons of stuff I need to manage on each for it to work. The element is just the visual output of the data inside of the object itself, that's all I really need it for.

Except that I need the object to perform an internal function when it's clicked. That seems to be the biggest source of my headache thus far.

Javascript:

function onClick(file) //The external onClick function I use to try to get it to call from. 
{
    file.state = INUSE;
    file.checkState();
}

function fileObject () { //The file object itself
    this.element;
    this.newElement();         
    //initialize stuff for the object
}

fileObject.prototype.newElement = function() { //creates a new element and sets its event listener
    this.element.click(function() {onClick(this)});
}

fileObject.prototype.checkState = function() {/*does stuff*/} //apparently this is "not a function"

The error I get exactly is "file.checkState is not a function" from Firefox's console panel.

I'm still new to javascript, but after doing some debugging, I've come to find out that it's explicitly the onClick(this) function that is causing all of the errors. When used with something else, the onClick function works perfectly, but for some reason, the this keyword doesn't appear to actually be sending the reference to the fileObject since all checks show file being undefined when inside of the onClick scope.

Is there something fundamentally wrong about the way I'm trying to do this or am I just missing a step (or adding something that I don't need) that will help get this snippet working.

Kats
  • 133
  • 12
  • 1
    Possible duplicate of [How does the "this" keyword work?](http://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – JJJ Oct 13 '16 at 05:51
  • Something like: when does `this` become `undefined`? – Tân Oct 13 '16 at 05:54
  • Okay, then I'm simply using `this` wrong, but that still doesn't solve my issue. All I need is a clean method of passing a reference to a function that will persist through the current scope. How do I do that? – Kats Oct 13 '16 at 05:55
  • 3
    `this.element.click` is not the way to set an event listener. –  Oct 13 '16 at 05:55
  • @torazaburo I'm not sure what you mean by that since it does exactly what I anticipate it to do: run a function when I click the element. – Kats Oct 13 '16 at 06:01
  • That would surprise me. You add an event listener with `element.addEventListener`. `element.click` actually emulates a click on the element. Anyway, what is the line `this.element` in `function fileObject` supposed to do? Where are you creating the element? Can you show the code where are you are constructing the `fileObject` object? –  Oct 13 '16 at 06:03
  • Everything I've posted is all of the exact pertinent code to the issue I'm having. I've already diagnosed the issue, I just don't have a solution for it. The element variable itself is a jquery object, which is why click() functions the way it does, not the raw javascript click() that does what you think. – Kats Oct 13 '16 at 06:09

2 Answers2

1

So you know, your initial problem isn't actually handling the action, but listening to it. click will trigger a synthetic click event, rather than liste for one.

You want ... .element.addEventListener("click", callback); that said, you face a second problem, immediately thereafter. I will leave my example code as you've written it to not confuse the matter...

But when you see click( ) know that I mean subscribing with addEventListener, if element really does mean a browser DOM element. If it's not a standard browser element, and your own API, then ignore the previous portion, and carry on.

this is dynamically bound at the invocation time of the function (not at definition time).

The nearest function, scoped above, is your callback function that you are passing into .click( ... ).

Which is entirely different than the this which you mean outside of the callback. Whatever is on the left-hand side of the dot is the this context for the duration of that particular invocation.

Needless to say, click() doesn't know enough to bind the this you mean, to the left-hand side of your callback.

The solution (or one of many) is to use lexical scoping and/or closure to retain the value of the object you mean.

// easy but messier
var fileObject = this;
... .click(function () { onClick(fileObject); });


// Cleaner with thunks:
function clickHandler (onClick, obj) {
  return function () { onClick(obj); };
}

... .click(clickHandler(this));
Norguard
  • 24,349
  • 4
  • 38
  • 45
  • Not sure what the `onClick` argument is for in the `clickHandler` function, but removing it finally solved my problem! I can't thank you enough! And now I understand more about closure and how to get around the intrinsic limitations of `this`! – Kats Oct 13 '16 at 06:16
  • Ahhh, sorry, it was meant to be a generic binding. It wasn’t the parameter that was off, it was the implementation. `clickHandler(onClick, fileObject)` the point being that you now have a generic way of remembering values and applying specific functions over them, lazily (by passing in a function which remembers both, and runs one over the other, when called). – Norguard Oct 13 '16 at 06:25
  • That makes more sense. I was just unsure what it was. Then again, I can't really blame you since I highly doubt you were able to test anything before posting a snippet. Lol. Fortunately I can still read by myself. Anyways, thanks again for helping me wrap my head around this not-so-object-oriented object oriented language. Lol. – Kats Oct 13 '16 at 06:27
  • Indeed. I’m on my phone, so I’m glad you can. The point was more that it worked when you removed it because the parameter happened to be named the same thing as what existed outside, within the function’s lexical scope, otherwise it would have thrown. But lexical scoping and higher-order functions (those constructed inside of other functions and returned, which hold closure references) are huge deals when you start writing environment-agnostic, functional JS. – Norguard Oct 13 '16 at 06:30
-2

Coming from c++ the way Javascript handles this will seem a little crazy, it looks like here you need to tell the function you've defined what this is - like so:

this.element.click(function() {onClick(this)}.bind(this));
Tom
  • 39,281
  • 4
  • 35
  • 60
  • I worry about the way to set an event to `this.element`. It seems like `not standard` – Tân Oct 13 '16 at 05:59