How to detect if any elements currently have mouseenter active? - javascript

So basically, I have an un-ordered list with around 12 list items. I would like to apply a style to them when the mouse is over any of them, and a different style when the mouse is over none of them.
For example, the following is my current code that only has a style when li's are being hovered.
HTML:
<ul>
<li>List item 1</li>
<li>List item 2</li>
<li>List item 3</li>
<li>List item 4</li>
<li>List item 5</li>
<li>List item 6</li>
</ul>
jQuery:
$('li').bind('mouseenter',function(){
$(this).animate({'opacity': '1'},100,'easeOutBack');
});
$('li').bind('mouseleave',function(){
$(this).animate({'opacity': '0.7'},600,'easeOutBack');
});
DEMO
I would like to style all the li to have opacity:1 when no li is being hovered over.
How can I achieve this?

You can do this with CSS only, if I understand correctly, you want to have all items at full opacity when none is hovered, and have full opacity on the one that's hovered and less opacity on the rest. Here's an example with just CSS:
li {
opacity: 1;
}
li:hover {
opacity: 1 !important;
transition: opacity .3s ease-in-out;
}
ul:hover li {
opacity: .5;
transition: opacity .3s ease-in-out;
}
Demo: http://jsfiddle.net/Sbgn8/2/

Is this what you want?
$('li').bind('mouseenter',function(){
$(this).animate({'opacity': '1'},100,'easeOutBack');
});
$('li').bind('mouseleave',function(){
$(this).animate({'opacity': '0.7'},600,'easeOutBack');
});
$("ul").bind('mouseenter',function(){
$("li").animate({'opacity': '0.7'},200,'easeOutBack');
})
$("ul").bind('mouseleave',function(){
$("li").animate({'opacity': '1'},200,'easeOutBack');
})

You can create a new class for the ul element that will cause all lis to be 100% opaque. Then, upon hovering a li, remove that class from the ul (its parent).
I'll give you a code if I sounded confusing.
Note that I've added a CSS transition, I suggest you do all of them using CSS (that way you won't have to deal with inline rules overriding all others).
$('li').bind('mouseenter',function(){
$(this).animate({'opacity': '1'},100);
$(this).parent().removeClass('full');
});
$('li').bind('mouseleave',function(){
$(this).animate({'opacity': '0.7'},600, function(){
$(this).css('opacity', '')
});
$(this).parent().addClass('full');
});
Here's what I had on my mind: http://jsfiddle.net/fqVT8/1/

Can't you just change the selector inside the handler function? Changing this...
$(this).animate({'opacity': '1'},100,'easeOutBack');
to this....
$('li').animate({'opacity': '1'},100,'easeOutBack');

Related

jQuery on click, add class but also remove if the class is already present

I have a nav menu that needs to trigger with clicks rather than hovers. When the links are clicked, an .open class would be added to the parent li. If that parent already has the .open class, then it would get removed. It would also be removed if another link is clicked on. So far I can get the class added when clicked and removed when a sibling is clicked, but not removed when it's already .open.
I tried adding a hasClass conditional, but that didn't work either. Seemed like it reruns the function every time it's clicked and therefore ignores the hasClass conditional.
Can anyone provide help? I tried toggleClass, but that didn't work.
$('li a').on('click', function() {
$('li a').parent().removeClass('open');
$(this).parent().addClass('open');
});
ul {
list-style: none;
}
li {
display: inline-block;
padding: 10px;
}
.open {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav>
<ul>
<li>
Item 1
</li>
<li>
Item 1
</li>
</ul>
</nav>
To do what you require you can use toggleClass() on the parent li when the element is clicked. To remove the class from all other li elements you can use removeClass() along with not() to exclude the current li. Try this:
$('li a').on('click', function() {
let $li = $(this).parent().toggleClass('open');
$('li').not($li).removeClass('open');
});
ul {
list-style: none;
}
li {
display: inline-block;
padding: 10px;
}
.open {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav>
<ul>
<li>
Item 1
</li>
<li>
Item 1
</li>
</ul>
</nav>
You can use
jquery toggleClass() to toggle yellow highlight (.open css class) on click/unclicking the same link.
jquery siblings() to remove .open class on all the other li items.
Below is the link for the demo
https://jsfiddle.net/so1u8hq6/
$('li a').on('click', function() {
$(this).parent().siblings().removeClass('open');
$(this).parent().toggleClass('open');
});
ul {
list-style: none;
}
li {
display: inline-block;
padding: 10px;
}
.open {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav>
<ul>
<li>
Item 1
</li>
<li>
Item 2
</li>
<li>
Item 3
</li>
</ul>
</nav>
Late to the party, but, after seeing the provided answers and some of the CSS you use I had to urge with my suggestions:
UX. Avoid styling LI tags in general, or at least set the desired display and move on. Style directly the a tag (with the necessary paddings etc.). You'll not only get less CSS to take care of, but also a larger touch interaction area. Makes no sense to style something yellow if it's not a UI part of something interactable. Also in JS, you don't need to take care about the LI wrappers any more - but only about the actual A Elements.
Don't use common selectors like $('li a') - those might target any LI→A elements in your app. Instead be more specific and use a Class like i.e: .tabs for the parent UL. Both in CSS and JS.
Try to use Event Delegation (in jQuey using the .on() method). Not only it will help you to catch the Event.delegateTarget parent UL where needed, but also the this (the clicked element), but mainly reference all the "group" of a elements enclosed in the common parent. That way you can have as many .tabs in a single page as you like. And yes, thanks to Event delegation you can even add dynamically LI Elements - and your JS will still work as expected.
Since you're using <a href="#"> Anchor elements, instead of (more properly) <button type="button>" Elements, you need to also use Event.preventDefault() in order to prevent the browser its default behavior and that's to follow anchors (scroll the page, navigate, etc...)
Use the selector "a.open" when you want to target and remove the "open" class. By just using "a" (or in other answers on this page - "li") you're uselessly touching elements trying to remove a class that's not there in the first place.
Finally, here's the CSS retouch and the proper jQuery needed for your task:
$(".tabs").on("click", "a", function(ev) {
ev.preventDefault();
$("a.open", ev.delegateTarget).not(this).removeClass("open");
$(this).toggleClass("open");
});
.tabs {
display: flex;
list-style: none;
padding: 0;
}
/* Style your Anchors, not the dummy LI wrappers */
.tabs a { padding: 10px; }
.tabs a.open { background-color: yellow; }
<ul class="tabs">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
To explain the only complicated line:
$(
"a.open", // Target just the ones (if any) of class "open"
ev.delegateTarget // inside the common ".tabs" ancestor
)
.not(this) // ... not the clicked element (since later we'll use .toggleClass on it)
.removeClass("open"); // ... remove that class "open"
the rest is pretty self explanatory.
Further read:
jQuery Event Delegation
jQuery event.delegateTarget
Event.preventDefault
So you only want the yellow background to appear as a signifier of user interaction rather than for the background color to be displayed? Have you tried using the mousedown/mouseup functions instead of .on('click', function(){...}?
I was able to simulate the click event where the color showcases via this method:
$('li a').mousedown(function() {
$('li a').parent().removeClass('open');
$(this).parent().addClass('open');
});
$('li a').mouseup(function() {
$('li a').parent().removeClass('open');
});
ul {
list-style: none;
}
li {
display: inline-block;
padding: 10px;
}
.open {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav>
<ul>
<li>
Item 1
</li>
<li>
Item 1
</li>
</ul>
</nav>

angular foreach list element

I have a HTTP request set up than after all promises are met will return the scope. In this case its a list of products.
My goal is to set these products to have an opacity of 0 initially, and then with the foreach add a class which will give them an opacity of 1.
What I currently have works with the ul element, but I cannot get it to with the child elements.
This is currently in my promise:
angular.forEach(angular.element(document.querySelector('.product-list')), function(value, key){
var a = angular.element(value);
a.addClass("loaded");
});
But no amount of playing with .product-list li etc will work.
Any ideas?
Example of the HTML is:
<ul class="product-list">
<li>item 1</li>
<li>Item 2</li>
<li>item 1</li>
<li>Item 2</li>
</ul>
And CSS:
.product-list {
li {
opacity: 0;
&.loaded {
opacity: 1;
}
}
}
And I will put a timeout in the foreach.
I think your css (SASS? LESS?) should be:
.product-list {
li {
opacity: 0;
}
&.loaded {
li {
opacity: 1;
}
}
}
as it looks like you are adding the loaded class to the ul element.

trigger visibility of sublist on class change

I've been trying to achieve this for the last two days, but I'm fairly new to javascript, so maybe I'm just not seeing something.
What I'm trying to create is a Sidenavigation, that highlights the current section you are at. I have found a jquery plugin that does that like a charm http://trevordavis.net/blog/jquery-one-page-navigation-plugin/
But I am working with subitems and I would like to trigger the visibility of this subitem, as soon as the current section is active. So the ul would be visible if the containing list item has the class of .current, and if one of the sublist's list items has the class .current.
I have found out, that I'd probably need to trigger an event on the class change. I have tried the following, but it has not yet worked.
Markup:
<ul id="nav">
<li class="current">Section 1</li>
<li>Section 2</li>
<li class="parent">Section 3
<ul class="sublist">
<li>Subsection 1</li>
<li>Subsection 2</li>
<li>Subsection 3</li>
</ul>
</li>
</ul>
For the jquery I have tried this:
$('#nav').on('event', function(){
$('.parent').addClass('current').trigger('visibility');
});
$('.parent').on('visibility', function(){
$('.parent .sublist').addClass('visible');
});
What I am basically trying to do is what Bootrap does in its documentation. When scrolling down, you can see Glyphicons, as soon as you reached this section, the subitems pop open (available glyphs, how to use, examples) http://getbootstrap.com/components/
SASS applied to the Navigation so far:
.overview{
transition: .3s all;
ul{
margin-left: 10px;
ul{
max-height: 0;
transition: max-height 1s ease-out;
overflow: hidden;
}
}
}
.current{
> a{
font-weight: $bold;
}
ul{
max-height: 9999px !important;
transition: max-height 1s ease-out;
}
}
I have been able to show the sublist if the parent is set to current, but as soon as the child is current, the sublist will be hidden, so I figured, I'd need some javascript
I see now :)
What you could do, (there's probably multiple way, but what I'd do) is create a function that checks on scroll if a class is nearing the top of the window, if so, add a class to the relating item in the nav bar.
Should be relatively simple to do without a plugin, something along the lines of:
var checkSide = function(){
$('.container p').each(function(){
var item = $(this).offset().top,
$window = $(window),
navItem = $('#nav a[data-id="'+$(this).data('id')+'"]');
if ($window.scrollTop() >= item) {
if (!navItem.hasClass('current')) {
$('#nav .current').removeClass('current');
navItem.addClass('current');
}
}
});
};
$(window).scroll(function(){
checkSide();
});
See http://codepen.io/jhealey5/pen/GjJFI - Should be able to adapt it to your needs.
Assuming I understood correctly :)

slideDown on a drop down menu

I want to do this(photoshop image) on my page:
On hover(over the ACTORS link) I want the yellow drop down list(where Fotis J.Colakides etc is) to show up slowly. From up till down.
I don't know what is the best way to do this on my page.
Of course I have to use an unorder list() like this:
<ul id="showInfoNav">
<li><a class="slideBtn" href="#">MEDIA</a>
<ul class="slideShow">
<li>assa</li>
</ul>
</li>
<li><a class="slideBtn" href="#">ACTORS</a>
<ul class="slideShow">
<li>ACTOR1</li>
<li>ACTOR2</li>
</ul>
</li>
</ul>
[Update]
Util now I have done this: (http://jsfiddle.net/bMGhC/)
But I am doing it from css. I have the left:-9999px; and on hover I am doing it left:0px;
I want to do it slideDown. But it is not working.
here is my css:
ul#showInfoNav
{
list-style:none;
float:left;
width:100%;
}
ul#showInfoNav li
{
float:left;
margin-right:50px;
position:relative;
}
ul#showInfoNav a.slideBtn
{
padding:5px;
display:block;
text-decoration:none;
}
ul#showInfoNav ul a:hover{
color:#898989;
}
/*--- DROPDOWN ---*/
ul#showInfoNav ul
{
background-color:#F4F9B6;
padding:50px 10px 10px 10px;
list-style:none;
left:-9999px; /* Hide off-screen when not needed (this is more accessible than display:none;) */
position: absolute;
top:-20px;
/*z-index:-1;*/
}
ul#showInfoNav ul li
{
float:none;
}
ul#showInfoNav ul a{
white-space:nowrap;
}
ul#showInfoNav li:hover ul{ /* Display the dropdown on hover */
left:0; /* Bring back on-screen when needed */
}
I have also this z-index problem. If I set it -1 it is hidden behind the image too.
Check out jQuery UI effects, specifically slide():
http://docs.jquery.com/UI/Effects/Slide
You could also look into the slideToggle() method that jQuery supplies.
See an example here.
Similar functions would be slideUp(), slideDown() and the more general, animate()
Take a look at .hover(), and .slideUp/Down(). You can also replace .hover with .toggle in the following code, if you'd like a more 'permanent' state. The key to both is utilizing their callback functions.
HTML
Click to see a list
<ul>
<li>List Item</li>
<li>List Item</li>
<li>List Item</li>
<li>List Item</li>
</ul>
jQuery
$('ul').hide(); // doing this rather than via CSS for a fail-safe for JS
$('a').hover(function() {
$('ul').slideDown('fast');
}, function() {
$('ul').slideUp('slow')
})​
When using jQuery fadeIn() you can specify the duration too.
Some simple sample would be:
Give the li's some id or class ( <li id="actor1">soemthing</li>)
In the JS file or script tag use:
$("#actor1).hover(function(){ $(this).slideDown('slow')}, function(){ $(this).slideUp('slow') });
EDIT: I see that you want a sliding effect so, I changed fadeIn() and fadeOut() to slideDown() and slideUp(). You can read their documentation here
This is the solution I found, I used this because I didn't want the <ul> to slideUp when I was navigating among his <li> tags.
$('ul.slideShow').hide();
$("#showInfoNav li").click(function () {
$(this).find('ul.slideShow').slideDown('fast').show();
$(this).hover(function () { // PARENT
}, function () {
$(this).parent().find("ul.slideShow").slideUp('slow'); //When the mouse hovers out of the subnav, move it back up
});
});

Show headers only for collections that are not empty

I have a couple of lists like this:
<ul>
<li class="list-header">Header</li>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
By some rules I hide and show <li> items so sometimes the list has visible <li> and sometimes it has no visible <li> elements at all except the one with list-header class, so <li class="list-header"> is still there. I want to hide that header if there are no <li> visible elements in it under header. Though I want the <ul> still to be visible.
How do I do that?
What you could do (demo):
$('ul').each(function() {
$ul = $(this);
$ul.find('.list-header').toggle($ul.has('li:not(.list-header):visible').length != 0);
});
Basically, what the above does is toggling the .list-header (I've wrapped it in the .each() in order to demo different lists) depending on whether the list .has() :visible li elements that are :not(.list-header).
UPDATE
Now it works. Sorry.
You could use the :visible and :not selectors to see if there are any elements present when you change the visibility. This example toggles the visibility when clicking the elements, and hides the header if there are no elements present:
$('li:not(".list-header")').click(function(){
$(this).toggle(10,function(){
var l = $(this).parent().children('li:visible:not(".list-header")').length
if (l>0) $(this).parent().children('li.list-header').show();
else $(this).parent().children('li.list-header').hide();
});
});
working example: http://jsfiddle.net/LDG4J/4/
There is no lh element in HTML. References: HTML5, HTML4.01, HTML 3.2. (You've removed the lh from the question.)
Instead, use an li with a class you style as you see fit (or if you're targeting recent-enough browses, no class required; just style li:nth-child(1) or li:first-child), and just don't hide that li (which will keep the ul visible):
<ul>
<li class='header'>Header</li>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
Update: I may have misunderstood. If you want to hide the header but keep the ul visible in some way:
A ul with no visible li elements will typically be invisible because it won't have any dimensions. You can override that with CSS, styling the ul to have a specific size (live example):
CSS:
ul.foo {
width: 5em;
height: 5em;
background-color: #eee;
border: 1px solid #aaa;
}
HTML:
<p><code>ul</code> with no visible children:</p>
<ul class='foo'>
<li style="display: none">This is hidden</li>
</ul>
<p><code>ul</code> with a visible child:</p>
<ul class='foo'>
<li>Visible child, note that it wraps</li>
</ul>
And of course you can apply that via jQuery rather than with a static CSS rule:
$("ul.foo").css({
width: "5em",
height: "5em",
backgroundColor: "#eee",
border: "1px solid #aaa"
});
...so you could do that when you're hiding all of the ul's elements, and undo it when showing at least one of them. After making a change:
var ul = $(/*...selector for the relevant list...*/);
if (ul.find('li:visible')[0]) {
// There's at least one visible `li` child
ul.css({/*...styles for when the list is not empty...*/});
}
else {
// There are no visible `li` children
ul.css({/*...styles for when the list is empty...*/});
}
...or better yet, add/remove a class.
try this:
$("ul li:not('.list-header')").each(function(index, val) {
if ($(this).text() == '') {
$(this).hide();
}
});
if (! ($('ul').has("li:visible:not('.list-header')").length)) {
$('li.list-header').hide();
}

Categories

Resources