so i have some html like this. ive added some classes for some clarity but their names are irrelevant. on mobile i want "sub-nav" to be a child of the "mobile parent" li. ive got it to appear after the li but not within it in the DOM structure. what am i missing? ive been messing around with the js, hasnt worked.
<ul class="main-nav">
<li>link 1</li>
<li>link 2</li>
<li class="mobile-parent>link 3</li>
</ul>
<ul class="sub-nav mobile-child">
<li>link 1</li>
<li>link 2</li>
</ul
let trigger = document.getElementById('trigger');
let nav = document.querySelector('.site-navigation');
let mobileChild = document.querySelector('.mobileChild');
let mobileParent = document.querySelector('.mobileParent');
trigger.addEventListener('click', function(){
trigger.classList.toggle('active');
if (trigger.classList.contains('active')) {
nav.classList.add('active');
} else {
if (nav.classList.contains('active')) {
nav.classList.remove('active');
}
}
});
if (window.innerWidth < 768) {
mobileParent.appendChild(mobileChild);
}
You can use the media query to show and hide elements for different devices.
Please refer the below code. And also refer this post.
.mobile-child-outer{
display:block;
}
.mobile-child{
display:none
}
#media screen
and (device-width: 360px)
and (device-height: 640px) {
.mobile-child-outer{
display:none;
}
.mobile-child{
display:block
}
}
<ul class="main-nav">
<li>link 1</li>
<li>link 2</li>
<li class="mobile-parent">link 3
<ul class="sub-nav mobile-child">
<li>link 1</li>
<li>link 2</li>
</ul>
</li>
</ul>
<ul class="sub-nav mobile-child-outer">
<li>link 1</li>
<li>link 2</li>
</ul>
Update
If you want the JS solution try the below. But, I don't think JS is a best solution for this, as you can achieve it with CSS.
window.addEventListener("resize", addSubNav);
function addSubNav(){
var width = document.body.clientWidth;
if (width < 768) {
document.querySelector('.mobileParent .mobile-child').remove();
mobileParent.appendChild(mobileChild);
}
}
Related
I have a left navigation menu using lists for each menu item.
I am making it so that the user can hide/unhide certain sub menus on the whole menu.
Unfortunately, when you hide one sub menu and then refresh the page, each sub menu takes on this current state instead of just that one. (vice versa when unhiding).
HTML:
<div>
<h1 class="toggler">Messaging</h1>
<ul class="tree">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</div>
<div>
<h1 class="tree-toggler">Information</h1>
<ul class="tree">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</div>
Script:
$(document).ready(function () {
if(localStorage.getItem("toggleState") == "1")
$('ul.tree').hide();
$('h1.toggler').click(function () {
var ts = localStorage.getItem("toggleState");
if(ts == null || ts == "0") {
var tv = "1";
localStorage.setItem("toggleState", tv);
}else {
var tv = "0";
localStorage.setItem("toggleState", tv);
}
$(this).parent().children('ul.tree').toggle(300);
});
});
How can I make it so that my code saves the state for each individual sub menu list chosen to hide/unhide?
<style> .toggler {cursor: pointer} </style>
<div>
<h1 class="toggler">Messaging</h1>
<ul class="tree">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</div>
<div>
<h1 class="toggler">Information</h1>
<ul class="tree">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</div>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script>
var clientStates = [];
$(document).ready(function () {
$('h1.toggler').click(function (e) {
$(this).parent().children('ul.tree').toggle(300);
setTimeout(function() {saveLocalStorage();}, 350); // wait until the animation is over, then save the state
});
loadLocalStorage();
});
function loadLocalStorage() {
toggleState = JSON.parse(localStorage.getItem("toggleState"));
if(typeof toggleState === 'object' ) {
clientStates= toggleState;
}
for(var i in clientStates) {
if(clientStates[i]) {
$('h1.toggler').eq(i).parent().children('ul.tree').show();
}
else {
$('h1.toggler').eq(i).parent().children('ul.tree').hide();
}
}
}
// read from the DOM if elements are visible or not. Save to localStorage
function saveLocalStorage() {
clientStates = [];
$('h1.toggler').each(function() {
if( $(this).parent().children('ul.tree').is(":visible") ) {
clientStates.push(true);
}
else {
clientStates.push(false);
}
});
localStorage.setItem("toggleState", JSON.stringify(clientStates));
}
</script>
Just a remark: the children of an UL should be LI elements, so put the A inside the LI
I have this slide up and slide down. I can slide down the child on click but cant slide up when click again.
JavaScript
jQuery("#all li").on("click", function(e) {
e.preventDefault();
var parent = jQuery(this);
var father = parent.data("clicked", true);
var child = parent.find("ul");
var x = child.on(":visible");
if (parent.is(":visible")) {
child.slideDown("fast");
} else {
child.slideUp("fast");
}
});
HTML
<nav>
<ul id="all">
<li>Link 1</li>
<li>Link 2
<ul>
<li>Sub-Link 1</li>
<li>Sub-Link 2</li>
<li>Sub-Link 3</li>
</ul>
</li>
<li>Link 3
<ul>
<li>Sub-Link 1</li>
<li>Sub-Link 2</li>
<li>Sub-Link 3</li>
<li>Sub-Link 4</li>
</ul>
</li>
<li>Link 4</li>
<li>Link 5</li>
<li>Link 6</li>
</ul>
</nav>
It seems to me, based on your posted script and markup, that the parent is always visible. This means the if statement has essentially no effect. Altering it to check if the child is visible may help:
$('#all li').on('click', function() {
var parent = $(this);
var child = parent.find('ul');
if(child.is(':visible')){
$(child).slideUp('fast');
} else {
$(child).slideDown('fast');
}
});
Fiddle Demo
To achieve your expected result, use slideToggle()
JS:
jQuery("#all li").on("click", function(e) {
e.preventDefault();
var parent = jQuery(this);
var father = parent.data("clicked", true);
var child = parent.find("ul");
var x = child.on("visible");
if (parent.is("visible")) {
child.slideDown("fast");
} else {
child.slideToggle("fast");
}
});
http://codepen.io/nagasai/pen/jAkjBd
What is a cool way to apply this? I need a script that exchange two < li>'s position in an < ul>.
It think that should be possible to achieve. Thanks for your response.
HTML
<div id="awesome">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
Pseudo Javascript (JQuery)
$("#awesome ul li:eq(1)").exchangePostionWith("#awesome ul li:eq(3)");
HTML Result
<div id="awesome">
<ul>
<li>Item 1</li>
<li>Item 4</li>
<li>Item 3</li>
<li>Item 2</li>
<li>Item 5</li>
</ul>
</div>
You can use jQuery's .after() for moving elements around. I cloned one of them so the original can remain as a placeholder. It's like if you wanted to switch variables a and b, you'd need a third temporary variable.
$.fn.exchangePositionWith = function(selector) {
var other = $(selector);
this.after(other.clone());
other.after(this).remove();
};
Now your pseudocode $("#awesome ul li:eq(1)").exchangePositionWith("#awesome ul li:eq(3)"); isn't so pseudo :-)
$("ul li a").click(function () {
$(this).parent().insertBefore('ul li:eq(0)');
});
<ul>
<li><a>a</a></li>
<li><a>b</a></li>
<li><a>c</a></li>
<li><a>d</a></li>
<li><a>e</a></li>
<li><a>f</a></li>
</ul>
I have an unordered list like this one:
Show the rest
<ul id="myList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
<li>Item 9</li>
<li>Item 10</li>
</ul>
and this jQuery code:
var list = $('#myList li:gt(4)');
list.hide();
$('a#myList-toggle').click(function() {
list.slideToggle(400);
return false;
});
The problem is that it slides each individual li item, i need to slide the rest of the list, like i would slide the whole list.
How can I do that?
your method didn't work because it would find the height with height: auto.
After a lot of fail and try, I came up with something that works, almost.
Do you have any comment on my code, I would really appreciate it.
And how would I do it, if I want the same link to collapse the list again
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
var list = $('ul#myList');
var original_height = list.height();
list.css({height:$('#myList li').height()*5});
$('a#myList-toggle').click(function() {
list.animate({height:original_height})
return false;
});
});
</script>
<style type="text/css">
ul#myList {
overflow: hidden;
}
</style>
</head>
<body>
Show the rest
<ul id="myList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
<li>Item 9</li>
<li>Item 10</li>
</ul>
</body>
</html>
Pretty clumsy solution IMHO, but if it works for you - it works for you...
For the list to collapse and expand by clicking on the same link:
$(document).ready(function() {
var list = $('ul#myList');
var original_height = list.height();
var new_height = $('#myList li').height()*5;
list.css({height:new_height});
$('a#myList-toggle').click(function() {
if( list.height() == original_height ) {
list.animate({height:new_height});
} else {
list.animate({height:original_height});
}
return false;
});
});
Quick & not-so-dirty way: wrap it with a div element and slideToggle('#myList div.wrapper').
You can give a height to UL tag with overflow:hidden. Then you use animation({height:auto}) to show all. Otherwise, you don't have any viable solution.
Whats the problem with simply toggeling the list instead of the elements?
$(function(){
var listheight = $("#mylist").height();
$("a#myList-toggle").toggle(function(){
$("#mylist").slideToggle();
},function(){$("#mylist").animate({height:listheight})});
});
The code expands and collapses a list in which list items can have sublists. Any ideas to refactor this code - especially the toggling part. Is it necessary to use closures here ?
$(function()
{
$('li:has(ul)')
.click(function(event){
if (this == event.target)
{
var that = this;
$('li:has(ul)').children().filter(':not(:hidden)').parent().each(function(x){
if(this != that)
toggleList(this);
});
toggleList(this);
}
})
.css({cursor:'pointer', 'list-style-image':'url(plus.gif)'})
.children().hide();
$('li:not(:has(ul))').css({cursor: 'default', 'list-style-image':'none'});
});
function toggleList(L)
{
$(L).css('list-style-image', (!$(L).children().is(':hidden')) ? 'url(plus.gif)' : 'url(minus.gif)');
$(L).children().toggle('fast');
}
EDIT:
The script works on the following HTML snippet (source: jQuery in Action). Actually I was trying to extend the script given in the book.
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>
Item 3
<ul>
<li>Item 3.1</li>
<li>
Item 3.2
<ul>
<li>Item 3.2.1</li>
<li>Item 3.2.2</li>
<li>Item 3.2.3</li>
</ul>
</li>
<li>Item 3.3</li>
</ul>
</li>
<li>
Item 4
<ul>
<li>Item 4.1</li>
<li>
Item 4.2
<ul>
<li>Item 4.2.1</li>
<li>Item 4.2.2</li>
</ul>
</li>
</ul>
</li>
<li>Item 5</li>
</ul>
Your code doesn't work for me in Safari. When I click on a sub-list, the top-list is toggled.
How about:
$(document).ready(function() {
$('li:has(ul)').click(function(event) {
$(this).css('list-style-image', $(this).children().is(':hidden') ? 'url(minus.gif)' : 'url(plus.gif)')
$(this).children().toggle('fast')
return false
})
.css({cursor:'pointer', 'list-style-image':'url(plus.gif)'})
.children().hide()
$('li:not(:has(ul))').click(function(event) { return false })
.css({cursor:'default', 'list-style-image':'none'})
})