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
Related
I'm trying to find a way to disable mouseenter when the top-level navigation item is clicked & on pageload and re-enable again when the mouse leaves and enters the element again.
User hovers over element = show submenu
User clicks menu = hide submenu and only show submenu when user leaves menu elements and enters again.
If user is over the element onLoad then only show submenu when user leaves element and enters again.
$('.navmenu li').on('mouseenter', function(e) {
$(e.target).next().addClass('js-hover')
}).on('mouseleave', function(e) {
$(e.target).next().removeClass('js-hover')
});
$('.navmenu').on('click', function(e) {
$(e.target).next().removeClass('js-hover')
location.reload(true);
})
.navmenu .submenu {
display:none;
}
.navmenu li {
display: inline;
}
.navmenu .submenu {
position:absolute;
top:40px;
left:0
}
.navmenu li:hover .js-hover {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav class="navmenu">
<ul>
<li>
Menu
<nav class="submenu">
<ul>
<li>Submenu 1</li>
<li>Submenu 2</li>
<li>Submenu 3</li>
</ul>
</nav>
</li>
<li>
Menu 2
<nav class="submenu">
<ul>
<li>Submenu 4</li>
<li>Submenu 5</li>
<li>Submenu 6</li>
</ul>
</nav>
</li>
</ul>
</nav>
this could be done using variables and storing a state of element (if it should be hidden or not). But since you tried to do this through class attributes, I did the same. Here is simle example of one menu item, everything should be clear.
<nav class="navmenu">
<ul>
<li>
Menu
<nav class="submenu" hidden>
<ul>
<li>Submenu 1</li>
<li>Submenu 2</li>
<li>Submenu 3</li>
</ul>
</nav>
</li>
</ul>
</nav>
and javascript:
$menuLink = $("nav.navmenu li > a");
$menuLink.click(function () {
$(this).addClass("dontHide");
});
$menuLink.mouseenter(function () {
$(this).next("nav.submenu").removeAttr("hidden");
$(this).removeClass("dontHide");
});
$menuLink.mouseleave(function () {
if(!$(this).hasClass("dontHide")) {
$(this).next("nav.submenu").attr("hidden", true);
}
});
Live demo: https://jsfiddle.net/g3fua461/24/
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);
}
}
Suppose I have a following structure:
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3
<ul>
<li>Item11</li>
<li>Item12</li>
<li>Item13</li>
</ul>
</li>
This tree structure can have many levels.
Initially, I want to show following list:
Item 1
Item 2
Item 3 +
When I click on + list becomes
Item 3 -
Item 11
Item 12
Item 13
So, parent list disappears and sublist is shown.
If I click -, then everything is returned to the previous list.
Is there some jquery plugin for doing this?
Perhaps, some options in accordion?
Thanks in advance.
Used Dkouk his version to create what you need.
EDIT 1: Hide other menu items
EDIT 2: Second level menu
$(function () {
$('ul li').each(function () {
if ( $(this).find('ul').length > 0 ){
$(this).addClass('child');
}
});
$('ul li.child span').click(function() {
$(this).parent().toggleClass('open').find('ul').first().slideToggle();
$(this).parent().siblings().slideToggle();
});
});
ul {
list-style:none;
}
ul li.child span:after {
content:"+";
}
ul li.child.open span:after {
content:"-";
}
li ul { display:none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul class="main">
<li>Item 1</li>
<li>Item 2</li>
<li>
<span>Item 3</span>
<ul>
<li>Item 1</li>
<li>
<span>Item 2</span>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</li>
<li>Item 3</li>
</ul>
</li>
</ul>
You can add a class to your list when it's have a sublist, and toggle the list and toggle another class for parent of list so can change the '+' to '-'.
You can as many levels, and the code will work,
I've add a span to the list have child, but so can trigger the click only at text, if you trigger click for LI list and have sublist open then will close again.
You can style the content.
Here a simple example :
$(function () {
$('ul li').each(function () {
if ( $(this).find('ul').length > 0 ){
$(this).addClass('child');
}
});
$('ul li.child span').click(function() {
$(this).toggleClass('open').parent().find('ul:first').slideToggle();
$(this).parent().siblings().slideToggle();
});
});
ul {
list-style:none;
}
ul li.child span:after {
content:"+";
}
ul li.child span.open:after {
content:"-";
}
ul li ul { display:none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>
<span>Item 3</span>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>
<span>Item 3</span>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</li>
</ul>
</li>
</ul>
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
I have two lists and when clicked on one element I want to remove it from this list and add it to a second one.
<div id="ul1">
<ul id="selected">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
<hr />
<div id="ul2">
<ul id="list2">
<li>Item 10</li>
<li>Item 20</li>
<li>Item 30</li>
<li>Item 40</li>
</ul>
</div>
I am not a jQuery dev and I can't have this working properly.
$("#ul1 a").click(function(){
var para1 = this.dataset['para1'];
$(this).closest('li').remove();
add2(para1);
return false;
});
$("#ul2 a").click(function(){
var para1 = this.dataset['para1'];
$(this).closest('li').remove();
add(para1);
return false;
});
function add(p1){
$("#selected").append('<li><a href="" data-para1='+p1+'>'+p1+'</a></li>');
return false;
}
function add2(p1){
$("#list2").append('<li><a href="" data-para1='+p1+'>'+p1+'</a></li>');
return false;
}
I would really appreciate if someone could point out the correct solution to accomplish this.
Here is a demo.
Thanks
Just use appendTo method.
$("#ul1").on('click', 'a', function(){
$(this).closest('li').appendTo('#list2');
return false;
});
$("#ul2").on('click', 'a', function(){
$(this).closest('li').appendTo('#selected');
return false;
});
Have a look at this snippet. It checks the click() event of the anchor inside the li, looks for the li by matching the father of the element.
$(document).ready(function() {
$('#select li a').each(function(index, anchor) {
// Let's add a click listener
$(anchor).click(function(){
// Let's find the father li
$(this).closest('li').appendTo('#append');
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="ul1">
<ul id="select">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
<hr />
<div id="ul2">
<ul id="append">
<li>Item 10</li>
<li>Item 20</li>
<li>Item 30</li>
<li>Item 40</li>
</ul>
</div>
Try this way :
$("#ul1 a").click(function(){
var para1 = $(this).closest('li').html()
$(this).closest('li').remove();
add2(para1);
return false;
});
$("#ul2 a").click(function(){
var para1 = $(this).closest('li').html()
$(this).closest('li').remove();
add(para1);
return false;
});
function add(p1){
("#list2").append(p1);
return false;
}
function add2(p1){
$("#list2").append(p1);
return false;
}
try:
function move(ul1,ul2) {
$('body').on('click',ul1+" a", function(){
$(ul2).append($(this).parent('li'));
//$(this).parent('li').remove();
return false;
});
};
move('#selected','#list2');
move('#list2','#selected');
https://jsfiddle.net/x9LL1ubc/2/