Reputation: 73
In an attempt to make my code drier, I've decided to take an if/else statement that I use often and turn it into a function. I tried applying this function to a forEach loop, however, I am getting an error that the function's parameter is undefined.
Here's the code:
var addClass = (className) => {
(this.classList.contains(className) === true)
? this.classList.remove('active') & this.classList.add(className)
: this.classList.add(className);
}
exploreStory_buttons.forEach(el => el.addEventListener('mouseover'), addClass(active));
Any insight into what I'm doing wrong would be greatly appreciated. As per usual, I feel as though the solution may be simple: that I'm just not seeing it.
Upvotes: 3
Views: 319
Reputation: 338248
You want to call the function in the proper context. There is Function#call
for that purpose. You also need to use a normal function, as "fat arrow" functions handle this
differently.
var addClass = function (className) {
if (this.classList.contains(className)) {
this.classList.remove('active');
this.classList.add(className);
} else {
this.classList.add(className);
}
}
exploreStory_buttons.forEach(el => {
el.addEventListener('mouseover'); // where is the event listener??
addClass.call(this, active); // N.B. active is undefined here. Do you mean "active"?
});
You also do not want to abuse language features to write "smart" code. Use if/else and multiple lines for multiple statements, you are not a code obfuscator.
Assuming you want to add a "hover" behavior, the code would have look something like this:
function addClass(className) {
return function () {
this.classList.add(className);
}
}
function removeClass(className) {
return function () {
this.classList.remove(className);
}
}
var activate = addClass('active');
var deactivate = removeClass('active');
exploreStory_buttons.forEach(el => {
el.addEventListener('mouseenter', activate);
el.addEventListener('mouseleave', deactivate);
});
Note how addClass
and removeClass
return functions that can serve as event handlers. Storing them into activate
and deactivate
variables means you are not creating multiple equivalent copies of a function inside the loop, but in fact assign the same function to all elements.
The activate
/deactivate
variables and function-returning functions can be avoided by implementing a hover()
function (jQuery has a similar feature):
function hover(elements, onenter, onleave) {
elements.forEach(el => {
el.addEventListener('mouseenter', onenter);
el.addEventListener('mouseleave', onleave);
});
}
hover(exploreStory_buttons, function () {
this.addClass('active');
}, function () {
this.removeClass('active');
});
Here the event handler functions are created only once and directly where they are needed. Much better than storing them in helper variables.
Upvotes: 6
Reputation: 1724
There are several issues with your code:
mouseover
you would like to change the class of the element to active. In this case addClass
function has to return another function, but regular one, not fat arrow, so this can be properly bound.Did you really wanted bitwise AND on this line:
this.classList.remove('active') & this.classList.add(className)
or logical AND?
exploreStory_buttons = document.getElementsByClassName('explore-story');
var addClass = (className) => function() {
this.classList.contains(className)
? (this.classList.remove('active') && this.classList.add(className))
: this.classList.add(className);
}
Array.prototype.forEach.call(exploreStory_buttons, (el) => el.addEventListener('mouseover', addClass.call(el, 'active')));
.active {
color: red
}
<button class="explore-story active">Story 1</button>
<button class="explore-story">Story 2</button>
Upvotes: 1