Jquery can't use 3 selectors - javascript

I'm writing a small script to make a mobile menu.
However I can't get my selectors to work together.
When I have $('#nav_button, .nav li, .nav li li') only #nav_button and .nav li works, however when I remove .nav li and leave $('#nav_button, .nav li li') this sub menu begins to work as well.
I have also tried using $('#nav_button, .nav li, .sub_menu li li') with the same results.
Does anyone have an idea why?
jquery:
var mobileMenu = function () {
var currentPosition = 'closed'
$('#nav_button, .nav li, .nav li li').click(function() {
if (currentPosition == 'closed') {
$('.nav').addClass('open');
currentPosition = 'open';
}
else {
$('.nav').removeClass('open');
currentPosition = 'closed';
}
});
};
html:
<div id="head">
<div class="container">
<div class="cover"></div>
<a href="#"><h1 class="logo pull-left">C<span class="logo_space">AV</span>O</h1>
</a> <!-- end logo !-->
<div id="nav_button"></div>
<ul class="nav pull-right">
<li>Menu
<ul class="sub_menu">
<li>Starters</li>
<li>Breakfast and Brunch</li>
<li>Salads</li>
<li>Sandwiches and Wraps</li>
<li>Pasta</li>
<li>Mains</li>
<li>Pizza</li>
</ul>
</li>
<li>About Us</li>
<li>Contact</li>
</ul>
</div><!-- end container !-->
</div> <!-- end header !-->

Firstly, two of your selectors match the same elements
$('#nav_button, .nav li, .nav li li')
.nav li matches any LI inside .nav, including nested LI's
.nav li li matches any LI's inside .nav that are inside another LI, i.e. nested LI's
In other words, LI elements inside LI elements, inside .nav are matched twice, but it shouldn't matter as jQuery removes duplicates, but it's uneccessary.
The real issue is that the event propagates, when you click a nested LI the event handler is called for the nested LI and the parent LI, so the click handler execute twice, and the class is first added, then removed (or vice versa) so there is no visible change.
Here's a simplified example
FIDDLE
Just doing
$('#nav_button, .nav li')
should be enough, but you have to add event.stopPropagation() to make sure the event doesn't propagate to the next parent LI when a LI is called, here's an example
FIDDLE
$('#nav_button, .nav li').on('click', function(e) {
e.stopPropagation();
// do stuff
});

As #adeneo said in nested li function will call twice unnecessarily. I think the other way to achieve this is divide click grabber in two selectors like below:
$('.nav').click(function() {
if (currentPosition == 'closed') {
alert('open');
$('.nav').addClass('open');
currentPosition = 'open';
}
else {
alert('close');
$(this).removeClass('open');
currentPosition = 'closed';
}
});
$('.nav > li > li').click(function() {
if (currentPosition == 'closed') {
alert('open');
$(this).addClass('open');
currentPosition = 'open';
}
else {
alert('close');
$('.nav').removeClass('open');
currentPosition = 'closed';
}
});
I wrote a fiddle to do what you expect. Please check and comment if that helpful.
http://jsfiddle.net/QMaster/y7d6osoq/

Related

HTML Node tree with add buttons and hierarchical numbering

How to create a JavaScript based tree where you have add buttons, to add extra child elements.
For example, it has to look like this:
I need do be able to add child elements, and I need to make number counting work like that also.
I tried jQuery click() and then added append(), but it didn't come out as I expected. It started randomly adding rows.
Is there a simple way to do this or am I just overthinking this too much? I'm new in coding and any help would be appreciated.
I started like below, but obviously it's not working like that:
$('document').ready(function() {
$('#parent').on('click', function() {
$('#tree').append('<li><input type="text"></li>')
$('#tree li:last').append('<button type="button" id="child">ADD</button>')
$('#tree li:last').append('<ul></ul>')
$('#child').on('click', function() {
$('#tree li ul').append('<li><input type="text"></li>')
$('#tree li ul li:last ').append('<button id="child2" type="button">ADD</button>')
$('#tree li ul li:last').append('<ul></ul>')
$('#child2').on('click', function() {
$('#tree li ul li ul').append('<li><input type="text"></li>')
$('#tree li ul li ul li:last').append('<button id="child3" type="button">ADD</button>')
$('#tree li ul li ul li:last').append('<ul></ul>')
$('#child3').on('click', function() {
$('#tree li ul li ul li ul').append('<li><input type="text"></li>')
});
});
});
});
});
ul {
list-style-type: decimal;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<ul id="tree"><button type="button" id="parent">ADD</button></ul>
</div>
The code repetition that you have is indeed a problem. You cannot do this indefinitely.
The solution is to create a generic click handler which will capture a click on any button that exists now or in some future.
For the nested numbering, you can use the counters() CSS-function.
As you are using jQuery, I would also suggest to rely more on the methods it provides:
$('document').ready(function(){
$('#tree').on('click', 'button', function() {
$(this).before(
$("<li>").append(
$("<ul>").append(
$("<button>").text("Add")
)
)
);
});
});
ul { counter-reset: item }
li { display: block }
li:before {
content: "node " counters(item, ".") " ";
counter-increment: item
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div><ul id="tree"><button id="parent">Add</button></ul></div>
This shows more "Add" buttons than in your image, as there are more places where content can be inserted. Every click on such a button will result in one more button.

JQuery .mouseover and .mouseout change font color

I am newbie to JQuery and I try to make some basic tricks with it. So basicly, I have simple navigation made of unordered list, and I want to change font color on currently mouseover-ed list item with JQuery, but I have problem because my JQuery script is changing font color of all list items, and I want to change font color of ONLY currently mouseover-ed list item, not all. I tried to get currently mouseover-ed list item, but I don't know how to implement it so that my JQuery change only that list item. Here are pictures:
What I currently have: http://i.imgur.com/8vWcOci.jpg
What I want: http://i.imgur.com/4yD0bIc.jpg
Here is my JQuery code:
$(document).ready(
function(){
$('.nav1 ul li').mouseover(
function () {
var index = $( ".nav1 ul li" ).index(this);
$('.nav1 ul li a').css({"color":"white"});
}
);
$('.nav1 ul li').mouseout(
function () {
var index = $( ".nav1 ul li" ).index(this);
$('.nav1 ul li a').css({"color":"#6291d8"});
}
);
}
);
Here is my HTML:
<nav class="nav1">
<ul>
<li>HOME</li>
<li>SERVICES</li>
<li>THERAPIES</li>
<li>GALLERY</li>
<li>BOOKING</li>
<li>CONTACT</li>
<li>ABOUT ME</li>
</ul>
</nav>
Instead of:
$('.nav1 ul li a').css({"color":"white"});
and:
$('.nav1 ul li a').css({"color":"#6291d8"});
use:
$(this).css({"color":"white"});
$(this).css({"color":"#6291d8"});
if you wan to apply css on achor tag:
$(this).find("a").css({"color":"white"});
$(this).find("a").css({"color":"#6291d8"});
By using $('.nav1 ul li a') you are changing all anchor tags css but but by using $(this) will change the current clicked element css.
Why JQuery?
use a:hover in css it is pretty cleaner.
Like:
.nav1 ul li a {
color: #6291d8;
}
.nav1 ul li a:hover{
color:white;
}
For all other links you can again use a and a:hover also a:active will give you additional functionality.
this is a special word in JavaScript that refers to the element that triggers an event. In jQuery you can use $(this). So you can replaceyour code with:
$(document).ready(function () {
$('.nav1 ul li a').hover(function () {
$(this).css("color", "white");
}, function () {
$(this).css("color", "#6291d8");
});
});
jsFiddle example
Notice that I also changed the selector to '.nav1 ul li a'. The anchors have their own default styling, so to override that you should target them, and not the parent list item. I also replaced your mouseover and mouseout with the hover method as it saves a few characters. Finally, I used the more basic single property version of .css() which also saves a few characters.
There is no need for JS here. You can use the CSS :hover psuedo class:
.nav1 ul li a {
color: #6291d8;
}
.nav1 ul li a:hover {
color: #FFF;
}
Example fiddle

Multiple dropdown navigation - how to change the trigger button

I am struggling with one of my dropdowns.
Currently it is set up to be triggered by an i tag to drop down the sub menu.
$('nav li i').click(function() {
I want to change it to (nav li a) so it is not the icon that has to be pressed
I also have the code:
var child = $(this).index('nav ul li i');
but i am not sure what to change this to?
You can see all the code in jsfiddle.
http://jsfiddle.net/susannalarsen/VNYAx/
Since I do not see the <a> element anywhere, I have changed the <i> to <a> for demonstration purposes. You can see the example on http://jsfiddle.net/VNYAx/3/
Basically I changed
$('nav li i').click(function() {
to
$('nav li a').click(function() {
And also
var child = $(this).index('nav ul li i');
to
var child = $(this).index('nav ul li a');
Is this what you need?
Instead of using the index of the icon as a way to identify which dropdown you want to slide down, you can save a reference to that dropdown by searching for '.dropdown' within the element clicked.
$('nav li').click(function () {
var $childDropdown = $(this).find('.dropdown');
if ($childDropdown.is(':visible')) {
$('.dropdown').slideUp(300);
} else {
$('.dropdown').slideUp(300);
$childDropdown.slideDown(300);
}
});
http://jsfiddle.net/9Fk7j/2/
Just an alternative approach to this problem using .slideToggle(). If you need anything explaining please comment and I will edit the answer. I have commented the JavaScript below. I also removed the extra <div> in the markup as the nested <ul> is a perfectly good container.
Demo
HTML
<nav id="moo">
<ul>
<li>Item A
<ul>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</li>
<li>Item B
<ul>
<li>Item 7</li>
<li>Item 8</li>
<li>Item 9</li>
</ul>
</li>
</ul>
</nav>
CSS
ul {
padding: 0;
margin: 0;
}
li {
display: inline;
}
nav li {
position: relative;
}
ul ul {
display: none;
position: absolute;
border:1px solid #ccc;
padding: 10px;
}
ul ul li {
display: block;
}
JavaScript
var $allSubMenus = $('ul ul'); // handle to all submenus
$('nav li a').click(function (e) {
var $li = $(this).closest('li'); // get parent <li> of the <a> clicked on
var $subMenu = $li.find('ul'); // get our submenu
$allSubMenus.not($subMenu).slideUp(300); // hide all other submenus
$subMenu.slideToggle(300); // show our submenu
e.stopPropagation(); // stop event bubbling further
});
$(document).click(function () {
$allSubMenus.hide(); // no need to reselect, just use handle
});

add two li elements into the end of the ul

here is the jsfiddle that I tried to do this: http://jsfiddle.net/fxMFh/
I want to add two li's into the end of the submenu with jquery, but this seems that doesnt navigate to the ul it needs to:
$(document).ready(function() {
$(".navigation_container nav > ul > li > ul").append('<li>test</li>');
});
this must be the problem:
$(".navigation_container nav > ul > li > ul")
I must be doing something very noobish here..
Try
$(document).ready(function() {
$(".navigation_container nav > ul > li > div.sub-menu > ul").append('<li>test</li>');
});
Demo: Fiddle
But probably I will shorten the selector to
$(document).ready(function() {
$(".navigation_container nav div.sub-menu > ul").append('<li>test</li>');
});
Demo: Fiddle
Three problems:
The fiddle doesn't include jQuery.
The selector is missing a div wrapper. It should be:
$(".navigation_container nav > ul > li > div > ul")
.appendTo() should be .append()
http://jsfiddle.net/ryanbrill/fxMFh/5/

jquery: don't run script, if it contains .active

I have a script that animates a menu. I don't want it to if the menu contains an object with an active class (.active). I can't figure it out. I have tried several things, but I guess I'm thinking all wrong. Can you help me?
This is the script:
$('#navigation .toplevel, #navigation > ul > li').each(function(idx) {
$(this).delay( idx * 600 ).fadeIn( 600 );
});
This is the markup:
<div id="navigation">
Menu
<ul class="undermenu">
<li>1.0 Menuitem
<ul>
<li>1.1 Menuitem</li>
<li>1.2 Menuitem</li>
</ul>
</li>
<li>2.0 Menuitem
<ul>
<li>2.1 Menuitem</li>
<li>2.2 Menuitem</li>
</ul> </li>
</ul>
</div>
If an UL does contain an active-class, I want it to be shown per default and the LI (the parent) to get an .active-class.
Does it make any sense?
*EDIT:*
The script shall not run if the main UL contains a child (or a childs child) with .active-class. I guess it's a IF/THEN matter? But I don't know how to write it.
And...
If "UL LI UL LI A" is active the "UL LI" (parents, parents, parent :D) should be given .active class. How do I do this?
Thank you in advance... :)
First, to assign the .active class to parent UL elements. You can simply change the selector below to iterate over your UL elements and add the .active class to their parent LI elements:
$('#navigation > ul > li .active').each(function(){
$(this).parent().addClass('active');
});
This will ensure that none of your .active tags are animated:
$('#navigation .toplevel, #navigation > ul > li').not('.active').each(function(idx) {
$(this).delay( idx * 600 ).fadeIn( 600 );
});
Add :not(.active) to your selector.
You can try it with the :not() selector of jQuery.
http://api.jquery.com/not-selector/
e.g. selecting li's not containing class active:
$('#navigation ul li:not(.active)').each...
Edit:
you can add an if clause like this:
if($('#navigation ul .active').size() != 0)
{
$('#navigation .toplevel, #navigation > ul > li').each(function(idx)
{
$(this).delay( idx * 600 ).fadeIn( 600 );
});
}
2.
$('ul li').has('ul li a.active').addClass('active');
something like this should work.
check out: http://api.jquery.com/size/, http://api.jquery.com/addClass/, http://api.jquery.com/has/
I believe this is what you want.
$('#navigation .toplevel, #navigation > ul > li').each(function(idx) {
$this = $(this);
if( $this.find('li.active').length === 0 ) {
$this.delay( idx * 600 ).fadeIn( 600 );
}
});

Categories

Resources