JavaScript get element from event trigger - javascript

I'm currently trying to programm my first Website.
Therefore I want to get all Elements with a certain class an give them all the same EventListeners.
I did that like this:
const certs = document.getElementsByClassName("certificate");
for (var i = 0; i < certs.length; i++) {
certs[i].addEventListener("mouseover", mouseOver());
certs[i].addEventListener("mouseout", mouseOut());
}
function mouseOver() {
this.querySelector(".overlay").classList.add("active");
}
function mouseOut() {
this.querySelector(".overlay").classList.remove("active");
}
My Problem is, "this" doesnt seem to be the element which is triggering the mouseOver event.
I also tried puting "this" as a parameter like here:
const certs = document.getElementsByClassName("certificate");
for (var i = 0; i < certs.length; i++) {
certs[i].addEventListener("mouseover", mouseOver(this));
certs[i].addEventListener("mouseout", mouseOut(this));
}
function mouseOver(elem) {
elem.querySelector(".overlay").classList.add("active");
}
function mouseOut(elem) {
elem.querySelector(".overlay").classList.remove("active");
}
Both ways didnt work and know I am stuck in a way...
Is there a way to do this?
How can I use the exact element triggering the event?
(I dont want to give every element a unique ID to make it reusable)

The second argument of addEventListener is a function. Right now, you're calling the function immediately, which returns undefined, so whenever you move your mouse over or out it attempts to run undefined. Pass just the function variable itself, addEventListener will handle calling the function later.
addEventListener calls the callback function with an Event object, which has the property target which is how you get your element.
const certs = document.getElementsByClassName("certificate");
for (var i = 0; i < certs.length; i++) {
certs[i].addEventListener("mouseover", mouseOver);
certs[i].addEventListener("mouseout", mouseOut);
}
function mouseOver(event) {
event.target.querySelector(".overlay").classList.add("active");
}
function mouseOut(event) {
event.target.querySelector(".overlay").classList.remove("active");
}

Related

Pass a counter from a for loop into an event listener

I'm trying to pass the counter into an event listener's parameter function. I know it is possible using an anonymous function for the click event but wanted to use a named function instead. I can't seem to figure this out or if it is possible. Is there any way to do this?
function addKeys(){
for(let i = 0; i < keys.length; i++){
keys[i].addEventListener("click", testing)
}
}
function testing(e){
console.log(e)
console.log(i)
}
You can bind a parameter to the function:
keys[i].addEventListener("click", testing.bind(null, i))
Now i will be passed as the first parameter, before any others:
function testing(i, e) {
...
}

Select this or variable in function

The listenerForm() function is executed with addeventlistener. In the function I get the "this" object for get the dom element. Now I need use this function but I need pass the dom element in parameters. How to difference if I pass a parameter?
for (var i = 0; i < form.length; i++) {
form[i].addEventListener("click", listenerForm,true);
}
function listenerForm(form) {
console.log(form); //result MouseEvent {isTrusted: true}
console.log(this);//result fomr element.
}
listenerForm(domElement);
If I execute function with addeventlistener, I only need get this. If I pass the form parameter, I only need parameter.
I found solution passing parameters in addeventlistener, but I can't create a function in for loop.
A solution using currying and the bind method is this
form.forEach(function(item){
item.addEventListener('click', listenerForm.bind(null, item));
})
now the first argument of listenerForm is the element clicked and this refers to the global object
If you don't need access to the event object (which it seems you don't?) then call the function from the event handler instead of using it as event handler:
form[i].addEventListener("click", function() {
listenerForm(this);
}, true);
Now the parameter form will always refer to the DOM element.
try this:
for (var i = 0; i < form.length; i++) {
form[i].addEventListener("click", listenerForm(this), true);
}
function listenerForm(clickedFormElement) {
console.log(clickedFormElement);//result form element
}
listenerForm(clickedFormElement);// i don't know what you're trying to do here!!

How to pass a parameter to a event's handler

How to pass a parameter to a event's handler?
Here's what am trying to do, but it doesn't work:
for (var i = 0; i < myobj.length; i++) {
myobj[i].onmouseover = myfun(myobj[i]);
}
The following doesn't work neither:
myobj[i].onmouseover = myfun.call(myobj[i]);
myobj[i].onmouseover = function () {myfun(myobj[i]);};
myobj[i].onmouseover = function () {myfun.call(myobj[i]);};
Am primarily interested in why it doesn't work, and solution in the same style.
Just use a creator function for your handlers to encapsulate the parameter to pass on.
function createHandler( param ) {
return function() {
myfun( param );
}
}
for (var i = 0; i < myobj.length; i++) {
myobj[i].onmouseover = createHandler( myobj[i] );
}
The reason your approach doesn't work is, because you don't pass on a function reference, but the result of a function call. So in your first example myfun( myobj[i] ) is evaluated and the result is passed on as the event handler.
I think, what you really mean is, that in case the event is fired, the function shall be evaluated. To do so you either have to pass the parameter via some global var or as a dataset property.
The cleaner solution, however, is to have a generator function as shown above.
Another approach is to use the fact that onmouseover will be invoked as a method (not a function) on the DOM element which fires the event.
In other words, write your code as if you expected someone to do this:
obj = xahlees();
obj.onmouseover();
Here's a solution:
for (var i = 0; i < myobj.length; i++) {
myobj[i].onmouseover = function() { myFun(this) };
}
I've uploaded a more complete example .

Javascript Closure Problem

I know this kind of question gets asked alot, but I still haven't been able to find a way to make this work correctly.
The code:
function doStuff () {
for (var i = 0; i< elementsList.length; i++) {
elementsList[i].previousSibling.lastChild.addEventListener("click", function(){
toggle(elementsList[i])}, false);
}
} // ends function
function toggle (element) {
alert (element);
}
The problem is in passing variables to the toggle function. It works with the this keyword (but that sends a reference to the clicked item, which in this case is useless), but not with elementsList[i] which alerts as undefined in Firefox.
As I understood it, using anonymous functions to call a function is enough to deal with closure problems, so what have I missed?
Try:
function startOfFunction() {
for (var i = 0; i< elementsList.length; i++) {
elementsList[i].previousSibling.lastChild.addEventListener(
"click",
(function(el){return function(){toggle(el);};})(elementsList[i]),
false
);
}
} // ends function
function toggle (element) {
alert (element);
}
The Problem is, that you want to use the var i! i is available in the onClick Event, (since closure and stuff). Since you have a loop, i is counted up. Now, if you click on any of the elements, i will always be elementsList.length (since all event functions access the same i )!
using the solution of Matt will work.
As an explanation: the anonymous function you use in the for loop references the variable "i" to get the element to toggle. As anonymous functions use the "live" value of the variable, when somebody clicks the element, "i" will always be elementsList.length+1.
The code example from Matt solves this by sticking the i into another function in which it is "fixated". This always holds true:
If you iterate over elements attaching events, do not use simple anonymous functions as they screw up, but rather create a new function for each element. The more readable version of Matts answer would be:
function iterate () {
for (var i = 0; i < list.length; i++) {
// In here, i changes, so list[i] changes all the time, too. Pass it on!
list[i].addEventListener(createEventFunction(list[i]);
}
}
function createEventFunction (item) {
// In here, item is fixed as it is passed as a function parameter.
return function (event) {
alert(item);
};
}
Try:
function doStuff () {
for (var i = 0; i< elementsList.length; i++) {
(function(x) {
elementsList[x].previousSibling.lastChild.addEventListener("click", function(){
toggle(elementsList[x])}, false);
})(i);
}
} // ends function
I think it might be an issue with passing elementsList[i] around, so the above code has a closure which should help.

adding onfocus event handler to every element

I'm getting an undefined message on all of my handlers. I want to bind a handler to every element and want to output the value. What is wrong with this code? Thanks!
for (var i = 0; i < document.forms[0].elements.length; i++ ){
document.forms[0].elements[i].onfocus = test(this);
}
function test(ele){
alert(ele.value);
}
You need to assign a function. At the moment you are assigning the return value of test(window) which is undefined.
onfocus = test;
Then reference the element inside the function:
function test(){
alert(this.value);
}
You need to change both the assignment and the function, since the element will no longer be passed in as a parameter, like this:
for (var i = 0; i < document.forms[0].elements.length; i++ ){
document.forms[0].elements[i].onfocus = test;
}
function test(){
alert(this.value);
}
As an event handler, this inside test will refer to the element you're dealing with, so just get the value from that.
The alternative version of your current approach would be the same test method, but with an anonymous function wrapper to pass the element itself as a parameter:
for (var i = 0; i < document.forms[0].elements.length; i++ ){
ddocument.forms[0].elements[i].onfocus = function() { test(this); };
}
function test(ele){
alert(ele.value);
}
As both Nick and David pointed out, the way you assign the event handler is not correct. However, to achieve what you are trying (pass in a context) you can use a delegate function. Like this:
for (var i = 0; i < document.forms[0].elements.length; i++ ){
var ele = document.forms[0].elements[i];
ele.onfocus = delegate(ele, test);
}
function delegate(obj, handler) {
return function () {
handler.call(obj);
}
}
function test() {
alert(this.value);
}
What the delegate function does, is call your handler function setting the context of this. See the documentation for the Function object for further information. For even further reading, I recommend The this keyword and Introduction to events on Quirksmode.

Categories