Navigation Menu using jQuery (from jQuery Cookbook) - javascript

The menu is supposed to show sub-items upon hover. Here's the code (from http://docs.jquery.com/Cookbook/Navigation):
<ul id="menu">
<li class="menu">Sub 1
<ul>
<li>test 1</li>
<li>test 2</li>
<li>test 3</li>
<li>test 4</li>
</ul>
</li>
<li class="menu">Sub 2
<ul>
<li>test 1</li>
<li>test 2</li>
<li>test 3</li>
<li>test 4</li>
</ul>
</li>
</ul>
jQuery code:
$(document).ready(function() {
var toggle = function(direction, display) {
return function() {
var self = this;
var ul = $("ul", this);
if( ul.css("display") == display && !self["block" + direction] ) {
self["block" + direction] = true;
ul["slide" + direction]("slow", function() {
self["block" + direction] = false;
});
}
};
}
$("li.menu").hover(toggle("Down", "none"), toggle("Up", "block"));
$("li.menu ul").hide();
});
What is this in the toggle function above? How is the code working? What is being selected by $("ul", this); ?

The "this" refers to the jQuery object $("li.menu") - when the hover method call applies the toggle function to that object. $("ul", this) selects ul elements that are children of the context provided in the second argument ("this"), thus it selects the ul elements nested within the li.menu elements. Hopefully that makes the hover/toggle functions make sense.

Related

SortableJS keep non draggable items fixed

I have a list created using SortableJS and has a few items which cannot be dragged and dropped. Here is an example of how it looks:
<ul id="user_selections">
<li class="no_drag">Fixed</li>
<li>Item 1</li>
<li class="no_drag">Fixed</li>
<li>Item 2</li>
<li class="no_drag">Fixed</li>
<li>Item 3</li>
<li class="no_drag">Fixed</li>
</ul>
Class no_drag are the items that are fixed.
Now when I move Items 3 above Item 1 the structure should be like this:
<ul id="user_selections">
<li class="no_drag">Fixed</li>
<li>Item 3</li>
<li class="no_drag">Fixed</li>
<li>Item 1</li>
<li class="no_drag">Fixed</li>
<li>Item 2</li>
<li class="no_drag">Fixed</li>
</ul>
Can anyone please help me how to achieve this kind of behaviour.
Here is the JS code I have tried:
var el = document.getElementById('user_selections');
if (el) {
const sortable = Sortable.create(el, {
filter: '.no_drag',
onMove(evt, oe) {
return evt.related.className.indexOf('no_drag') === -1;
},
preventOnFilter: false,
onEnd: function(/**Event*/evt) {
// Some ajax call to save the new indexes
}
});
}
I have found a solution that works perfectly for first and last elements.
Add this in options:
onMove: function(e) {
if(e.related.classList.contains('no_drag')) {
return false;
}
},
If drop target is something you don't want moved it will return false, i.e. it will be ignored as drop target.
Elements in the middle will also be ignored, but you can still target elements after (or before) them, so they will be moved.

How to make dropdown menu with 3 levels?

I have a simple menu, and I want to do that when you click on the menu items to open a nested list. If you double-click then it must be opened and closed.
Html:
<ul class="menu">
<li class="has-child">Click here
<ul>
<li class="has-child">Click here
<ul>
<li>Level 3</li>
</ul>
</li>
<li>Level 2</li>
<li>Level 2</li>
</ul>
</li>
<li>Level 1</li>
<li>Level 1</li>
</ul>
jQuery:
$('li.has-child').on('click', function () {
var elem = $(this).children('ul');
if (elem.is(':hidden')) {
elem.slideDown(500);
} else {
elem.slideUp(500);
}
});
But when I click on a menu item in the second level, then the first is closed. Why is this happening and how to fix it?
[JSFiddle]
You need to stop the event from propagating from the parent to the child or vice-versa. You can use event.stopPropagation():
$('li.has-child').on('click', function (event) {
event.stopPropagation()
var elem = $(this).children('ul');
if (elem.is(':hidden')) {
elem.slideDown(500);
} else {
elem.slideUp(500);
}
});
you need to use stopPropagation
$(document).ready(function () {
$('li.has-child').on('click', function (event) {
event.stopPropagation();
var elem = $(this).children('ul');
if (elem.is(':hidden')) {
elem.slideDown(500);
} else {
elem.slideUp(500);
}
});
});
This then stops the click bubbling up to the parent li
Fiddle

Progressive reveal with jQuery

I have nested unordered list.
<ul id="catalogue">
<li>List
<ul>
<li>Item 1</li>
<li>Item 2
<ul>
<li>Item 1.1</li>
<li>Item 1.2
<ul>
<li>Item 1.2.1</li>
<li>Item 1.2.2
<ul>
<li>Item 1.2.2.1</li>
</ul>
</li>
<li>Item 1.2.3</li>
</ul>
</li>
<li>Item 1.3</li>
</ul>
</li>
<li>Item 3</li>
</ul>
</li>
</ul>
At the beginning only the very top level shows, but if you click on each LI, if there's a child UL in it, it should display the next lever, and so on. If you click on the same LI again, the level below should become hidden.
$(document).ready(function () {
$('#catalogue li').each(function () {
$(this).contents().first().wrap("<span/>")
});
$('#catalogue li > span').addClass('brd');
$('ul').hide();
$('#catalogue').show();
$('#catalogue li').click(function () {
var nxt = $(this).children('ul:first')
if ($(nxt).is(":visible")) {
$(nxt).slideUp();
} else {
$(nxt).slideDown();
}
$(this).parent().show();
});
});
If a user clicks on a sibling LI and it has a child UL, that UL should show but any sibling's ones should close.
You need to stop the event from propagating to the parent. Clicking on each li will invoke its own click handler and the event will propagate to its parent li invoke its handler and so on. So you can just stop it at one level by using event.stopPropagation(). And you can use slideToggle to toggle the current state of the element.
Try:
$('#tree li').click(function (e) {
e.stopPropagation();
$(this).children('ul:first').slideToggle();
});
Demo
And if you want to slide up while clicked on its sibling then,
$('#tree li').click(function (e) {
e.stopPropagation();
var $this = $(this);
$this.children('ul:first').slideToggle().end()
.siblings().children('ul:visible').slideUp();
//Code Broken down
//$this.children('ul:first').slideToggle();
//$this.siblings().children('ul:visible').slideUp();
});
Demo

Fade in/out list of DOM elements one at a time

I've got a web page with a large list of hidden li elements that I'd like to endlessly loop over and display on a small visible list of 5 li elements. I'm currently using a recursive method that calls itself with the next li element after each update which works fine to fade in/out each visible li one at a time forever. However once I try to change the html in the visible li to the html in the hidden li that I'm looping over all hell breaks loose. All 5 visible li's get set to the first 5 hidden li's and fade in/out all at once. Then there is a long pause, the page freezes for a bit and eventually all 5 visible li's will fade in/out again and still be set to the first 5 hidden li's. It's like once I try to change the html all of a sudden the entire looping happens all at once and I can't perceive why that would be the case.
$(function () {
fade($("#all-donors").first(), 1);
});
function fade(elem, curItem) {
var curElement = $("#donor" + curItem);
//curElement.html(elem.html()); //This line breaks it
curElement.fadeOut(1000).fadeIn(1000, function () {
curItem++;
if (curItem > 5) {
curItem = 1;
}
// If we're not on the last <li>
if (elem.next().length > 0) {
// Call fade on the next <li>
fade(elem.next(), curItem);
}
else {
// Else go back to the start
fade(elem.siblings(':first'), curItem);
}
});
}
To Loop LI's from just 1 <UL> element, and to loop <LI> tags from 2 <UL> elements, using the first UL as a visible UL and the 2nd UL as the looper UL
1ST APPROACH
JSFIDDLE FINAL RESULT HERE
Fade in, only after fading out is complete. And use class to hide all li elements except the first li initially and no need to send the curItem parameter to the function, which could only mess things up, just send the .next or :first element to the function instead. And no need to use .length > 0, .length is good enough.
$(document).ready(function() {
myFunc($(".show"));
});
function myFunc(oEle)
{
oEle.fadeOut('slow', function(){
if (oEle.next().length)
{
oEle.next().fadeIn('slow', function(){
myFunc(oEle.next());
});
}
else
{
oEle.siblings(":first").fadeIn('slow', function(){
myFunc(oEle.siblings(":first"));
});
}
});
}
HTML:
<ul class="listitem">
<li class="show">Test 1</li>
<li class="hidden">Test 2</li>
<li class="hidden">Test 3</li>
<li class="hidden">Test 4</li>
</ul>
2ND APPROACH, and answer to your question!
JSFIDDLE FINAL RESULT HERE
jQUERY:
var curIndex = 0,
nextIndex = 0;
$(document).ready(function() {
myFunc($(".show").children().eq(curIndex), $(".hidden").children().eq(nextIndex));
});
function myFunc(curLI, nextLI)
{
curLI.fadeOut('slow', function(){
$(this).html(nextLI.html()).fadeIn('slow', function() {
curIndex = curLI.next().length ? ++curIndex : 0;
nextIndex = nextLI.next().length ? ++nextIndex : 0;
myFunc($(".show").children("li").eq(curIndex), $(".hidden").children("li").eq(nextIndex));
});
});
}
HTML STRUCTURE:
<ul class="listitem show">
<li>Blah 1</li>
<li>Blah 2</li>
<li>Blah 3</li>
<li>Blah 4</li>
<li>Blah 5</li>
</ul>
<ul class="listitem hidden">
<li>Test 1</li>
<li>Test 2</li>
<li>Test 3</li>
<li>Test 4</li>
<li>Test 5</li>
<li>Test 6</li>
<li>Test 7</li>
<li>Test 8</li>
<li>Test 9</li>
<li>Test 10</li>
<li>Test 11</li>
<li>Test 12</li>
<li>Test 13</li>
<li>Test 14</li>
</ul>
CSS:
.listitem {
list-style-type: none;
list-style: none;
}
ul.hidden li {
display: none;
}
Sorry, guess I didn't fully understand what you were asking for exactly. Well, hopefully this helps someone, if not you.
Here, I think this is what you're looking for.
It can be changed for your needs, but it's the basic thing working.
JSFiddle (updated): http://jsfiddle.net/Ut86V/4/
HTML:
<ul class="list1">
<li>blahxx</li>
<li>blahxxx</li>
<li>blahxxxx</li>
<li>blahxxxxx</li>
<li>blahxxxxxx</li>
</ul>
<ul class="list2">
<li>blah1</li>
<li>blah2</li>
<li>blah3</li>
<li>blah4</li>
<li>blah5</li>
<li>blah6</li>
<li>blah7</li>
<li>blah8</li>
<li>blah9</li>
<li>blah0</li>
<li>blah11</li>
<li>blah12</li>
<li>blah13</li>
<li>blah14</li>
<li>blah15</li>
<li>....</li>
</ul>
Javascript:
function popList( speed ) {
speed = speed || 2000;
var $list1 = $('.list1 li');
var $list2 = $('.list2 li');
var item = 0;
var source = 0;
for( i=0; i<5; i++ ) {
$list1.eq( i ).html( $list2.eq( i ).html() );
source = i+1;
}
var replaceContent = function() {
$list1
.eq( item )
.delay( speed/2 )
.animate(
{ opacity: 0 },
speed/4,
function() {
var content = $list2.eq( source ).html();
$(this)
.html( content )
.animate(
{ opacity: 1 },
speed/4
);
item = ( item >= 4 ) ? 0 : item+1;
source = ( source >= $list2.length-1 ) ? 0 : source+1;
replaceContent();
}
);
};
replaceContent();
};
$(function() {
popList(5000);
});

Copy element's attributes to other element in javascript loop

I have a problem in loop js. I would like to copy data-icon value from .nav class to li in #item-control. Is there anyway easy way to solve it with jquery?
<div id="nav-container">
<ul class="nav">
<li data-icon="images/1.png">Item 1</li>
<li data-icon="images/2.png">Item 2</li>
<li data-icon="images/3.png">Item 3</li>
</ul>
</div>
<div id="item-control">
<li>Item Control 1</li>
<li>Item Control 2</li>
<li>Item Control 3</li>
</div>
What I've tried:
$(document).ready(function () {
var a = 1;
$('#container #nav-container ul.nav li').each(function () {
var item_control = $(this).parent().parent().parent().find('#item-control li');
item_control.addClass('item' + a); //this is what I tried before adding data-icon attributes to #item-control li
a++;
});
});
var $navItems = $('.nav li'),
$itemControlItems = $('#item-control li');
$.each($navItems, function(index, el) {
$($itemControlItems[index]).data('icon', $(el).data('icon'));
});
Fiddle

Categories

Resources