Mouseover event over multiple elements flickers - javascript

I’m stuck creating code that’s lean and want to use only JavaScript for now.
http://jsfiddle.net/TheOne_TheMany/30zdkrys
The problem I’m having is the mouseover state, when it goes over the <li> it works, but flickers when going over the <div> delete area. I know why it does that(After lots of research). So I tried mouseleave, but I need to have multiple ID on the <li> to make it work.
Is there a cleaner way of coding without creating so many ID or multiple event listeners. Especially if I'm going to add more <li> or delete them.
Thanks in advance for the help.

The issue is that the child <div> is in front of the <li> when you hover it, so the target is not a <li>, but a <div>. I'd strongly recommend you to use hover in CSS instead of JavaScript to solve it, but since you want like this, here you go:
Inside the mouseOver function, add another if statement to check if the mouse is inside delete button. Then, you add the classes to the <li> and the button.
const mouseOver = function(item){
// Btn animation'
if (item.target === btnSend) {
item.target.classList.add('btnOver');
}
// Li animation
if (item.target.matches('li')) {
item.target.classList.add('onLi');
item.target.lastChild.classList.add('containerDelete');
}
if (item.target.matches('.deleteMe')) {
item.target.parentNode.parentNode.classList.add('onLi');
item.target.classList.add('containerDelete');
}
item.stopPropagation;
}
Then, on mouseLeave function, add another if statement to check if the mouse is leaving from the <li> and delete button.
Inside it, you can also check if the the target is the <li> or the button <div>, because you have to remove the classes differently.
const mouseLeave = function(item){
// Btn animation
if(item.target === btnSend){
item.target.classList.remove('btnOver');
} else if (!item.toElement.matches('li') && !item.toElement.matches('.deleteMe')) {
if (item.target.tagName === 'LI') {
item.target.classList.remove('onLi');
item.target.lastChild.classList.remove('containerDelete');
}
if (item.target.tagName === 'DIV') {
item.target.parentNode.parentNode.classList.remove('onLi');
item.target.parentNode.classList.remove('containerDelete');
console.log('ok')
}
}
}

Related

Elements blocking div I'm trying to hover on?

Absolutely stumped here...
I have a dynamically generated list of divs. It goes through each of those divs and applies an event listen on hover. Inside each of those divs is some text, a H1, some body copy and a link. Unfortunately the trigger only fires if I hover on a bit of 'blank space' in the div where there's no text.
I've tried pointer-events:none which does fix the issue but doesn't solve an issue where I have a link. Essentially I just want the whole div to respond when hovered. I swear I've done this before?!
Here's a video demonstrating: Video Recording
Here's how my JS is set up (the projectsText is getting each project element)
projectsText.forEach(project => {
project.classList.remove("active")
})
event.target.classList.add("active")
}
const changeWorkImage = (event) => {
projects.forEach(image => {
if (image.id === event.target.id) {
workImage.style.backgroundImage = "url(" + image.heroImage + ")"
} else {
return
}
})
}
projectsText.forEach(project => {
project.addEventListener('mouseover', (event) => {
changeWorkImage(event)
changeActive(event)
})
})
And how my component is structured
<div className="project" id={id}>
<p className="company">{company}</p>
<h2 className="title">{title}</h2>
<LearnMore url={url} />
</div>
The mouseover event goes to one, and only one, event handler at a time. It gives priority starting with the innermost child (nested/z-index). If you move the cursor from a parent ("project") to one of its children ("title"), then the parent loses the focus of the mouseover event.
There is a similar event, mouseenter which ignore transitions within an element. In other words, it doesn't pay attention when you move the mouse over children elements, so it in effect works from the outside in. This may work better in your case. (The converse, mouseleave, can be used to detect when the mouse has left.)

How to use .not() Jquery Selector on triple selector class?

I have an issue with two buttons that share common html classes. Both buttons are part of a tutorial. As the tutorial goes through the steps the Skip button appears first. as the tutorial gets to the last step before moving on to anew tutorial page, the 3rd party JS package dynamically adds another class to the skip button and changes the inner html to Continue. My issue is below
One button is:
<a class="introjs-button introjs-skipbutton" role="button" tabindex="0">Skip</a>
The other button is
<a class="introjs-button introjs-skipbutton introjs-donebutton" role="button" tabindex="0">Continue</a>
These buttons are part of a tutorial guide with certain steps. They are not displayed at the same time. However, clicking the Skip button fires the same action as the Continue button, as displayed in the JS code below. I'd like the action to only Fire when the Skip button is clicked but it keeps firing on both and I cant figure out how to figure it out.
I'd like a certain action to fire but only fire when <a class="introjs-button introjs-skipbutton> is fired and NOT <a class="introjs-button introjs-skipbutton introjs-donebutton> is fired.
$("a.introjs-button.introjs-skipbutton").not(".introjs-donebutton").click(() => {
console.log('skipbuttontriggered')
this._app.skipTutorial = true;
})
I've tried various combinations and was hoping to get some insight on using the not() selector for triple stacked html classes.
You don't need to use :not(). You could just check it doesn't have the class.
$("a.introjs-button.introjs-skipbutton").click(() => {
if ( ! $(this).hasClass('introjs-donebutton') {
console.log('skipbuttontriggered')
this._app.skipTutorial = true;
}
})
The hasClass() documentation can be read here.
If you're adding and removing the introjs-donebutton class dynamically, you can do it with event delegation and a selector with :not().
$(document).on("click", "a.introjs-button.introjs-skipbutton:not(.introjs-donebutton)", () => {
console.log('skipbuttontriggered')
this._app.skipTutorial = true;
})

jQuery doesn't recognise that the class changed, although the Browser does

I have been trying out to create a Dropdown-menu with jQuery. I have 3 Sub-folders with 3 sub-sub-folders each (correct me if this is the wrong term). Depending on wether the Sub-folder is collapsed (Sub-subs invisible) or expanded (Sub-subs visible) there´s a little arrow pointing downwards when expanded and to the right when collapsed. I´m a Newbie and don´t want to use many external scripts, so I remove the Subshown_arrow Class and add the Subhidden_arrow Class when clicked (or the other way).
<img id="arrow" class="Subshown_arrow" /> Sub-forum 1
<li class="sub-sub"> <a href="#"> Sub-sub-forum 1 <li>
<li class="sub-sub"> <a href="#"> Sub-sub-forum 2 <li>
<li class="sub-sub"> <a href="#"> Sub-sub-forum 3 <li>
I removed the scr here ^, normally it´s there.
var main = function() {
$(".Subshown_arrow").click(function() {
alert("Subshown_arrow clicked!");
$(this).removeClass("Subshown_arrow").addClass("Subhidden_arrow");
});
$(".Subhidden_arrow").click(function() {
alert("Subhidden_arrow clicked!");
$(this).removeClass("Subhidden_arrow").addClass("Subshown_arrow");
});
};
$(document).ready(main);
However, when I click the Arrow for the first time, it rotates as expected. But when I click it another time, jQuery reacts as if it was clicked for the first time. The alerts print out "Subshown_arrow clicked!" every time.
But when I tried it out in the Browser and used Chrome´s built-in tools to view the Code, the Class changed. That means that changing the Class works, but my jQuery script ignores it.
What have i done wrong? Or is there a better way to do it?
Your problem has already been solved thousands of times, you are binding to .Subhidden_arrow and .Subshown_arrow classes when the first doesn't exist yet. You need to bind the events differently:
$('body').on('click', '.Subhidden_arrow', function ( e ) {});
This will work also on dynamically created (changed) elements.
If you use .on it will work when classes changes as new handler will be assigned to it. but when you use .click it is assigend to the object that had the matching class at first and although the class has changed but still the old handler is assigned to it.
var main = function() {
$("body").on("click",".Subshown_arrow",function() {
alert("Subshown_arrow clicked!");
$(this).removeClass("Subshown_arrow").addClass("Subhidden_arrow");
});
$("body").on("click","Subhidden_arrow",function() {
alert("Subhidden_arrow clicked!");
$(this).removeClass("Subhidden_arrow").addClass("Subshown_arrow");
});
};
You are using an img without any src and if you have more images then i would mention to not to use same ids.
So, what you can do is give a common class name to the element:
<img class="arrow Subshown_arrow" />
<!----------^^^^^-------like this one---->
Now you can use the class arrow to bind the click event and you can use toggleClass() method to change the classes:
$(".arrow").click(function() {
$(this).toggleClass("Subshown_arrow Subhidden_arrow");
});
As mentioned the problem is that the click is bound on document load, at which time there are no elements with a class subhidden_arrow. This can indeed be solved by using a parent elements click and a filter on the class using (on). However, the original bound click event can also be reused to toggle the classes:
$(".Subshown_arrow").click(function() {
$(this).toggleClass("Subshown_arrow").toggleClass("Subhidden_arrow");
});
The click is bound to the element on load and reacts on both 'states', regardless of which class it holds then.
An example Fiddle with a slight alteration to make the containing anchor react to the click event.
Better way
var main = function() {
$("#arrow").click(function() {
$(this).toggleClass("Subshown_arrow").toggleClass("Subhidden_arrow");
});
};
$(document).ready(main);

Why can't jquery remove these classes?

I have created a series of elements that when you click on any one of them, they will expand, pushing the other elements out of the way. Initially if you clicked on it again the element would contract, but now I want to take the close functionality and put it in a button with in the element.
Initially when you click on the element, I use jQuery to add a number of classes to a variety of elements.
$(".left > .elem").click(function () {
$(this).addClass("expand");
$(this).parent().addClass("WithLarge");
$(this).children(".bar").addClass("visible");
$(this).children(".reduce_button").addClass("visible");
$(".right").addClass("shift_right");
});
When I click the close button I would like to remove those classes.
$(".reduce_button").click(function () {
$(this).parent().removeClass('expand');
$(this).parent().removeClass("WithLarge");
$(this).parent().children(".bar").removeClass("visible");
$(this).parent().children(".reduce_button").removeClass("visible");
}
The problem is, those classes aren't budging.
You can try it out on the JSFiddle
Click on the yellow box(".left > .elem"), it expands pushing the others out of the way, click on the red box(".reduce_button"), and nothing happens. I tried
console.log($(this).parent().hasClass('expand'));
$(this).parent().removeClass('expand');
console.log($(this).parent().hasClass('expand'));
to see if it has been removed. It returns false, even though the class is still there.
Why can't I remove these classes?
You ARE removing the class. But, the click on the .reduce_button is also triggering the .elem click event, which adds the class back again.
EDIT:
As commented below by j08691, you can add stopPropagation to keep the event of going on to the next listener, like:
$(".reduce_button").click(function (e) {
$(this).parent().removeClass('expand');
e.stopPropagation();
...
Here is your fiddle updated: http://jsfiddle.net/HybHK/9/

Jquery click function exclude children

Hey I'm having an issue figuring this one out.
JS
$('.jrm-menu-categories,#overlay-2').click(function() {
$('#overlay-2').toggle();
$('#overlay-3').hide();
});
HTML
<ul id="megaUber" class="megaMenu">
<li id="menu-item-1459" class="jrm-menu-categories">
<ul class="sub-menu sub-menu-1">
So basically what my JS does is create an overlay/modal effect when a sub menu is opened via click. I have the code repeated a few times with different classes and overlay ids hence the last line of code (needed so that only one overlay is shown at a time). Quickest and simplest way for a beginner like me, but that's not the subject.
When a sub-menu is open, and a user clicks anywhere in the sub-menu it toggles the overlay. I'm assuming this is because when I selected .jrm-menu-categories in the JS, it also selected the child elements, which happen to be .sub-menu
I'm thinking I need to use the .not() function, but can't figure it out.
can you guys help me with this? if possible write the code so I can try it out
Thanks!
You can try adding a second click handler to the children that will always return false. That way the click won't propagate up and dismiss:
$('.jrm-menu-categories').children('.sub-menu').click(function (e) {
e.stopPropagation(); // prevent click propagation, so parent click never fires.
})
You can test for the clicked item.
$('.jrm-menu-categories,#overlay-2').click(function(e) {
if (this == e.target){
$('#overlay-2').toggle();
$('#overlay-3').hide();
}
});

Categories

Resources