jQuery: hasClass logic issue - javascript

I'm building a dropdown menu and checking for classes etc. I'm having an issue where a condition is false, but it's being treated as true.
With the below code snippet, follow these instructions:
Click on "item 1"
Click on the plus icon above "more"
Click on "item 1" again
You'll notice that if you try to reopen the menu by clicking on "item 1" the menu does not open. Why? Those list items do NOT have a class of "show"... so those should open, irregardless of the second submenu, correct?
I'm not understanding what's wrong with my logic. I don't think this is a syntax error because there are no errors in console.
See below:
$(function() {
// main expansion element
$(".expander").click(function() {
var subShown = $("ul > li", this).hasClass("show");
if (!subShown) {
$(".indented", this).slideDown('100').addClass("show");
$(".caret", this).addClass("reversedCaret");
} else {
$(".indented", this).slideUp('100').removeClass("show");
$(".caret", this).removeClass("reversedCaret");
}
});
// sub expansion element
$(".sub-expander").click(function() {
var subSelectText = $(".more-or-less").text();
if (subSelectText != "More") {
$(".indented--sub").slideUp('100').removeClass("show");
$(".sub-caret").removeClass("reversedCaret");
$(".more-or-less").text("More");
} else {
$(".indented--sub").slideDown('100').addClass("show");
$(".sub-caret").addClass("reversedCaret");
$(".more-or-less").text("Show Less");
}
});
// stop propagation on the link element within .expander class
$(".indented").click(function(event) {
event.stopPropagation();
});
});
.expander:hover {
cursor: pointer;
}
.sub-expander--indented {
padding: 0 0 0 23px;
}
.sub-caret {
margin-right: 75px;
}
.indented,
.indented--sub {
display: none;
}
.show {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div class="expander">
<span class="caret downCaret right visibleCaret">+</span>
<ul>
<li class="category">Item 1
</li>
<li class="indented">Item 2</li>
<li class="indented">Item 3
<ul class="sub-expander more" style="padding-top:
0px;">
<li class="indented--sub">Chapter 5</li>
<li class="indented--sub">Chapter 6</li>
<li class="indented--sub">Chapter 7</li>
<span class="sub-caret moreCaret visibleLessCaret right">+</span>
<li class="more-or-less less sub-expander--
indented">More</li>
</ul>
</li>
</ul>
</div>

https://jsfiddle.net/3z0zo2gn/
} else {
$(".indented", this).slideUp('100').removeClass("show");
$(".caret", this).removeClass("reversedCaret");
$(".indented--sub").slideUp('100').removeClass("show");
$(".sub-caret").removeClass("reversedCaret");
$(".more-or-less").text("More");
}
As stated in the above comment, you need to remove the show class from indented--sub when removing it from indented.

Your code don't work because you didn't remove class show in li with class indented--sub

Related

Expand all / collapse all lists for class not working

I have a tree list where the user can open or close the branches by clicking. The tree has many levels and sub-levels. I want to be able to collapse all branches (down to the first level) or expand all branches for the class "my-clickable" when the user clicks on the Collapse All or Expand All button.
I can get the individual branches to close or open. But I can't get them all to open or close at once.
Here is my jsfiddle:
https://jsfiddle.net/dyrh325f/65/
One thing to note is that the Expand All button is being used after an ajax call that populates the entire tree. I have the 'Expand All' code in the "done" portion of the ajax call, so it applies to the generated html.
I want the user to be able to expand the entire tree out after he has closed one or more nodes. I've tried several variations of what I have in my jsFiddle. Nothing seems to work. What am I doing wrong?
I am a jQuery newbie so - thanks for any and all help!!!
Code:
HTML:
Expand Tree
<font face="calibri" size="3pt" >
<ul id="tree1" class="mytree">
<li id="theJob" class="my-clickable mytree liParOpen">My Job</li>
<ul id="treeList" class="mytree" name="treeList">
<li id='0' class='mytree child-click'>Batcher</li>
<li id='1' class='mytree child-click'>Retriever</li>
<li id='2' class='my-clickable mytree liParOpen'> TASK 2</li>
<ul class='mytree'>
<li id='2a' class='mytree child-click'>Prep1</li>
<li id='2b' class='mytree child-click'>Prep2</li>
<li id='2c' class='mytree my-clickable liParOpen'>PREP3</li>
<ul class='mytree'>
<li id='2b1' class='mytree child-click'>PREP3a</li>
<li id='2b2' class='mytree child-click'>PREP3b</li>
</ul>
</ul>
<li id='3' class='mytree child-click' > task 3</li>
<li id='4' class='my-clickable mytree liParOpen'> TASK 4</li>
<ul class='mytree'>
<li id='4a' class='mytree child-click'>Edit1</li>
<li id='4b' class='mytree child-click'>Edit2</li>
</ul>
<li id='5' class='my-clickable mytree liParOpen'> TASK 5</li>
<ul class='mytree'>
<li id='5a' class='mytree my-clickable liParOpen'>Del1</li>
<ul class='mytree'>
<li id='5a1' class='mytree child-click'>Del1a</li>
<li id='5a2' class='mytree child-click'>Del1b</li>
</ul>
<li id='5b' class='mytree child-click'>Del2</li>
</ul>
<li id='6' class='mytree child-click'>DocEjector-3</li>
</ul>
</ul>
</font>
Jquery:
$(document).ready(function(){
// expand button
$('#expandTree').on('click', function(event) {
var all = $('.my-clickable');
var closed = all.filter('.liParClosed');
closed.find("ul").each(function(){
$(this).next('ul').attr("class", "liParOpen");
$(this).nextAll('ul').toggle();
});
}); // end expand button
// collapse button
$('#collapseTree').on('click', function(event) {
var all = $('.my-clickable');
var open = all.filter('.liParOpen');
open.find("ul").each(function(){
$(this).next("ul").attr("class", "liParClosed");
$(this).nextAll('ul').slideToggle();
});
}); // end collapse button
// this is the top most level parents
$(".my-clickable").on('click', function(event) {
var taskId=$(this).closest("li").attr('id');
var tsk = '#'.concat(taskId);
if (taskId != "theJob") {
if ($(tsk).next('ul').length <= 0) {
$(tsk).toggleClass("liParOpen liParClosed");
$(tsk).next('ul').slideToggle();
}
else {
//$(event.target).find('ul').toggle();
$(tsk).toggleClass("liParOpen liParClosed");
$(tsk).children('li').slideToggle();
$(tsk).next('ul').slideToggle();
}
} // end if taskId != "theJob"
else {
$(tsk).toggleClass("liParOpen liParClosed");
$(tsk).slideToggle();
}
event.cancelBubble=true;
event.stopPropagation();
});
//2nd level parents
$(".my-clickable").on('click', ".my-clickable", function(event) {
var taskId=$(this).closest("li").attr('id');
var tsk = '#'.concat(taskId);
//$(event.target).find('ul').slideToggle();
$(tsk).toggleClass("liParOpen liParClosed");
//event.cancelBubble=true;
event.stopPropagation();
});
// first level child w/no children (parent=job)
$(".child-click").on('click', function(event) {
event.stopPropagation();
});
});
CSS:
ul.mytree li.liParClosed {
background-color: green;
fontWeight: normal;
}
ul.mytree li.liParOpen {
background-color: cyan;
fontWeight: normal;
}
.selected{
border: 3px solid yellow;
background-color: yellow;
fontWeight: bold;
}
ul.mytree liParOpen selected{
border: 3px solid red;
background-color: yellow;
fontWeight: bold;
}
ul.mytree li selected{
border: 3px solid red;
background-color: yellow;
fontWeight: bold;
}
ul.mytree li {
background-color: white;
fontWeight: normal;
}
ul.mytree {
background-color: white;
fontWeight: normal;
}
You almost got it but the toggling of classes "liParClosed" and "liParOpen" wasn't being done right.
Here's a fiddle fixing that issue:
JS Fiddle
Relevant code changes:
// expand button
$('#expandTree').on('click', function(event) {
var all = $('.my-clickable');
var closed = all.filter('.liParClosed');
closed.each(function(){
$(this).removeClass('liParClosed').addClass('liParOpen');
$(this).next('ul').slideToggle();
});
}); // end expand button
// collapse button
$('#collapseTree').on('click', function(event) {
var all = $('.my-clickable');
var open = all.filter('.liParOpen');
open.each(function(){
$(this).removeClass('liParOpen').addClass('liParClosed');
$(this).next('ul').slideToggle();
});
}); // end collapse button
Look at the way the classes are being added/removed. Also, you were
looking for open.find("ul") BUT open itself had to be looped through as it is a list of open li's.
Hope this helps. :)

On click, making a menu disappear on menu. The "show" works, but the "hide" doesn't

I have a portfolios item inside my menu, which then becomes a dropdown menu on hover for desktop and click for mobile. The problem with mobile is that the first click shows the menu, which is all good, but the next clicks don't change anything.
I've tried .toggle(), .toggleClass(), both of which don't seem to work. I'm currently testing out an if/else statement, shown in the JavaScript below. "If the window width is less than 940px"... and then "if the current visibility is hidden, change it to visibility: visible on click of the parent" and vice versa for the else.
Edit:
I'm only testing this in browser windows that are less than 940px to emulate the "mobile" experience.
Edit #2:
I removed the if window width < 940px for the purposes of this question since it might be easier to respond to that way?
$(function() {
if ($('.nav__portfolio ul').css('visibility', 'hidden') == true) {
$('.nav__portfolio').on('click', function() {
$('.nav__portfolio ul').css('visibility', 'visible');
});
} else {
$('.nav__portfolio').on('click', function() {
$('.nav__portfolio ul').css('visibility', 'hidden');
});
}
};
.nav__portfolio ul {
visibility: hidden;
<li class="nav__portfolio"><p>PORTFOLIO</p>
<ul>
<li>Dropdown Item</li>
<li>Dropdown Item</li>
<li>Dropdown Item</li>
</ul>
</li>
I guess your main problem is the condition you pass to the if statement:
$('.nav__portfolio ul').css('visibility', 'hidden') isn't a boolean so it doesn't return true or false
What you can do is compare the actual value for that css property like this:
$('button').on('click', function() {
if ($('div').css('visibility') !== 'hidden') {
$('div').css('visibility', 'hidden');
} else {
$('div').css('visibility', 'visible');
}
})
div {
height: 200px;
margin: 20px 0;
background: #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Toggle the div</button>
<div></div>
This logic on your actual code will be something like:
$('.nav__portfolio').on('click', function() {
if ($('.nav__portfolio ul').css('visibility') == 'hidden') {
$('.nav__portfolio ul').css('visibility', 'visible');
} else {
$('.nav__portfolio ul').css('visibility', 'hidden');
}
})
Have you tried hasClass/addClass/removeClass instead?
probably only need one click listener
if ($(window).width() <= 940) {
$('.nav__portfolio').on('click', function() {
if ($('.nav__portfolio ul').hasClass('visibleClass') {
$('.nav__portfolio ul').removeClass('visibleClass');
} else {
$('.nav__portfolio ul').addClass('visibleClass');
}
});
}
.nav__portfolio ul {
visibility: hidden;
}
.nav__portfolio ul.visibleClass {
visibility: visible;
}
With the toggle() method:
$('.nav__portfolio').on('click', function() {
$('.nav__portfolio ul').toggle();
})
.nav__portfolio ul {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<li class="nav__portfolio"><p>PORTFOLIO</p>
<ul>
<li>Dropdown Item</li>
<li>Dropdown Item</li>
<li>Dropdown Item</li>
</ul>
</li>

a little trouble with mouseover event

my codes are working correctly but in the change of requirement.
i need to keep current active class active which is removed again i mouseover at active <li>
i am not good in JQuery so can somebody help doing this??
(function($){
$(document).ready(function(){
$('a.form').on('mouseover', function(event) {
event.preventDefault();
event.stopPropagation();
$(this).parent().siblings().removeClass('active');
$(this).parent().toggleClass('active');
});
});
})(jQuery);
li.active .btncss, .btncss:hover {
color: #FFAE00;
background: #ffffff;
border: 2px solid;
text-decoration: none;
}
li{display:inline}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list-inline">
<li class="active">With In City</li>
<li class="">Full Day Hire</li>
<li class="">Half Day Hire</li>
<li class="">InterCity Hire</li>
</ul>
Use addClass instead of toggleClass.
.toggleClass Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the state argument.
.addClass() Adds the specified class(es) to each element in the set of matched elements.
It's important to note that this method does not replace a class. It simply adds the class, appending it to any which may already be assigned to the elements.
Try this:
(function($) {
$(document).ready(function() {
$('a.form').on('mouseover', function(event) {
event.preventDefault();
event.stopPropagation();
$(this).parent().siblings().removeClass('active');
$(this).parent().addClass('active');
});
});
})(jQuery);
li.active .btncss,
.btncss:hover {
color: #FFAE00;
background: #ffffff;
border: 2px solid;
text-decoration: none;
}
li {
display: inline
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list-inline">
<li class="active">With In City
</li>
<li class="">Full Day Hire
</li>
<li class="">Half Day Hire
</li>
<li class="">InterCity Hire
</li>
</ul>
It's a little hard to understand your question -- do you want the <li> that is originally active to be reset as active on mouseout? To do this, you need to record what was originally active and add a mouseout handler:
(function($){
$(document).ready(function(){
var originally_active = $('li.active');
$('a.form').on('mouseover', function(event) {
event.preventDefault();
event.stopPropagation();
$(this).parent().siblings().removeClass('active');
$(this).parent().toggleClass('active');
});
$('a.form').on('mouseout', function() {
$(this).parent().removeClass('active');
originally_active.toggleClass('active');
});
});
})(jQuery);
li.active .btncss, .btncss:hover {
color: #FFAE00;
background: #ffffff;
border: 2px solid;
text-decoration: none;
}
li{display:inline}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list-inline">
<li class="active">With In City</li>
<li class="">Full Day Hire</li>
<li class="">Half Day Hire</li>
<li class="">InterCity Hire</li>
</ul>

Javascript/jQuery cancel a function in another

I have a function that on hover, it shows the image next to the list item. That works fine. However, I need to have it so that when the user clicks the link, the image stays there. As of right now when the user clicks the link the hover function still prevails and the image will only show if the link is being hovered over.
$('[href]').hover(function() {
$(this).closest('li').prev('li').removeClass('hidden');
}, function() {
$(this).closest('li').prev('li').addClass('hidden');
});
$('[href]').click(function(ev) {
ev.preventDefault();
$(this).closest('li').prev('li').removeClass('hidden');
});
ul, li {
list-style: none;
display: inline-block;
}
.hidden {
visibility: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="hidden"><img src="https://placehold.it/30x30" /></li>
<li>Link</li>
</ul>
This happening because hover overwrites click. I create this solution so when click the link the image remains visible:
var clickHref = false;
$('[href]').hover(function() {
$(this).closest('li').prev('li').removeClass('hidden');
}, function() {
if (!clickHref)
$(this).closest('li').prev('li').addClass('hidden');
});
$('[href]').click(function(ev) {
ev.preventDefault();
$(this).closest('li').prev('li').removeClass('hidden');
clickHref = !clickHref;
});
ul,
li {
list-style: none;
display: inline-block;
}
.hidden {
visibility: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="hidden">
<img src="https://placehold.it/30x30" />
</li>
<li>Link
</li>
</ul>
Probably the off method fit your needs:
$('[href]').click(function(ev) {
ev.preventDefault();
$(this).off("mouseenter mouseleave").closest('li').prev('li').removeClass('hidden');
});

How to cancel a CSS style set by 'hover child' selector on event?

I am making a CSS based menu, with submenu items that pop up when the root element is hovered. the problem I have is that I want the CSS menu to close when I click an item in the list, but at that point I am still technically hovering over the top element, so I figured I had to use javascript to hide the menu. But when I set the display property, I set it forever and it overrides the hover selector of the parent node. And so the submenu doesn't show up anymore.
This must be pretty common, but I can't find any answers...
Any help much appreciated!
html:
<ul class="level1">
<li>one
<ul class="level2">
<li id="test">two</li>
<li>three</li>
</ul>
</li>
</ul>
css:
.level1 li:hover > ul {
display: inline;
}
.level2 {
display: none;
}
js:
document
.getElementById('test')
.addEventListener('click',function () {
this.parentNode.style.display = 'none';
// After this the menu doesn't open anymore
// because the style is overriden
});
Here's the jsfiddle
You can try this.
<ul class="level1">
<li class="hoverMe">one
<ul class="level2">
<li id="test">two</li>
<li>three</li>
</ul>
</li>
</ul>
.hoverMe:hover > ul {
display: inline;
}
var test = document.getElementById('test');
test.onclick = function () {
this.parentNode.parentNode.className = "";
};
var level1 = document.getElementsByClassName('level1')[0];
level1.getElementsByTagName("li")[0].onmouseover = function () {
if (this.className != "hoverMe") {
this.className = "hoverMe";
}
};

Categories

Resources