I have a JS function where I try to use this
which is supposed to be the button clicked to trigger the function:
function myAction( greeting ) { console.log( greeting + ", the button is :" + this ); this.remove(); }
I then have several buttons on my page, let's say two (this really even happens with only two buttons on the page; I've tested it):
<button id="button-one" class="click-me">Click Me</button>
<button id="button-two" class="click-me">Click Me</button>
From my experience, when I want to use event listener callbacks which require the use of the concerned element as this
plus other function arguments; if we have several buttons sharing for example the same class; the best way to reach this is to bind that callback as a closure (to capture the iterated element as this
+ apply (to deliver the concerned this
element):
var myButtons = document.getElementsByClassName( "click-me" );
var amountOfButtons = myButtons.length;
for ( var i = 0; i < amountOfButtons; i++ ) {
myButtons[i].addEventListener( "click", (
function(i) {
return function() { myAction.apply( myButtons[i], ["hello"] ); };
}(i))
);
}
I never had any problem with this approach; it always worked. Is it actually the wrong approach?
Because, what I'm facing now is that, when I click on #button-one
, and then click on #button-two
, this
actually becomes undefined in strict mode and the window in non-strict mode; on the second click. When I do it the other way around, this
always sticks to be the accordingly clicked button. It somehow seems to update the myButtons
collection, such that when the first button gets removed via the first call, the 1
index becomes unavailable in the collection, as there's only one remaining button; the other one being removed. At least that's my theory. But I've never faced this issue before in similar code cases? How shall I code what I want to happen then?
EDIT
Thanks to all of you; and special thanks to @Nenad Vracar, as his solution led to the minimum needed edits which perfectly work, by simply changing:
var myButtons = document.getElementsByClassName( "click-me" );
var amountOfButtons = myButtons.length;
for ( var i = 0; i < amountOfButtons; i++ ) {
myButtons[i].addEventListener( "click", (
function(i) {
return function() { myAction.apply( myButtons[i], ["hello"] ); };
}(i))
);
}
To:
var myButtons = document.getElementsByClassName( "click-me" );
var amountOfButtons = myButtons.length;
for ( var i = 0; i < amountOfButtons; i++ ) {
myButtons[i].addEventListener( "click", function() {
myAction.apply( this, ["hello"] );
});
}
Simple smart solution, I could literally not see the wood for the trees! thanks again!
Note. Event delegation was not really an option here, as the DOM structure of the page / the elements needing the attachment is somewhat complicated, and I generally prefer to attach the function to the elements needing it. Also, I prefer to not change the code of the function to be a closure itself, to not make changes to the function code itself. Hence the reason why I've decided to use this solution.