jQuery Expanding & Collapsing lists - javascript

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'})
})

Related

Trying to parse tag element

I am trying to parse a web page with JavaScript targeting list <li> without class.
<ul id="cartItems">
<li class="heading">
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
</ul>
Use querySelectorAll to get all li elements without a class.
var liWithoutClass = document.querySelectorAll('#cartItems > li:not([class])');
console.log(liWithoutClass);
document.write(liWithoutClass[0].textContent); // Output the first li
document.write('<br />' + liWithoutClass[3].textContent); // Output the last li
<ul id="cartItems">
<li class="heading">Heading</li>
<li>Element 1</li>
<li>Element 2</li>
<li>Element 3</li>
<li>Element 4</li>
</ul>
var elems = document.querySelector(".heading");
console.log(elems);
//Now we strip the class out like this:
elems.setAttribute(class, "none");
//Now we display the updated values below
console.log(elems);
// This won't work in Stack's editor, so you'll have to validate it against the page you want.
//Now, just grab the entire element by id from the page as below:
var updatedContent = document.getElementById("cartItems");
console.log(updatedContent);
//Again, stack's editor is limited, but overall this should work fine on your page.
<ul id="cartItems">
<li class="heading">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
</ul>

Having problems using $.each and wrapInner() in jQuery Mobile

I'm trying to iterate through a list of elements and wrap them in a link tag. However, my list displays differently than I want to.
Here is what it should look like: http://jsfiddle.net/eMexU/
HTML
<div id="list" data-role="listview">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</div>
Here is what it looks like when I use $.each and wrapInner(): http://jsfiddle.net/zpFDa/1/
HTML
<div id="list" data-role="listview">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</div>
JS
$("#list li").each(function () {
$(this).wrapInner('')
});
The only way to do this, is replacing existing li with new ones and then call .listview('refresh') to apply styles / enhance markup.
Demo
$("#list li").each(function () {
var text = $(this).text();
$(this).replaceWith('<li>' + text + '</li>')
});
$('#list').listview('refresh');

JavaScript: Slide a UL down to last element

Can't think how best to do this. Thought it would be a simple show/hide but it dosn't seem as simple as that.
There is a UL with an indeterminable amount of items in it. It needs to be able to show the first 10 but no more unless a 'show more' button is clicked. When the 'show more' button is clicked it will expand the list open to show the complete list.
http://jsfiddle.net/kbUhW/
Interested to see how this is achieved.
Here is an example: http://jsfiddle.net/WqxGf/
JS:
count = 0;
$('ul li').hide();
$('ul').children().each(function(){
if(count >= 10) return;
$(this).show();
count++;
})
$('.slide').click(function(){$('ul li').show('blind');})
HTML:
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
<li>Item Four</li>
<li>Item Five</li>
<li>Item Six</li>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
<li>Item Four</li>
<li>Item Five</li>
<li>Item Six</li>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
<li>Item Four</li>
<li>Item Five</li>
<li>Item Six</li>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
<li>Item Four</li>
<li>Item Five</li>
<li>Item Six</li>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
<li>Item Four</li>
<li>Item Five</li>
<li>Item Six</li>
</ul>
<a href="#" class='slide'>Slide Down</a>
All the other answers use jQuery, but your question didn't actually specify it. So here's one way to do it with plain JavaScript. Let's assume your <ul> has the ID foo, your "reveal" link has the ID reveal, and that there's a class hide with display: none. Then we have:
(function getChildNodes(id, num) { // ID of element, number to show
var obj = document.getElementById(id),
children = obj.childNodes,
elemcounter = 0;
for (var i = 0; i < children.length; i++) { // loop all children
if (children[i].nodeType === 1) { // examine elements only
elemcounter++;
if (elemcounter > num) { // element number in range to hide?
children[i].className = 'hide';
}
}
}
}('foo', 3)); // id foo, show 3
document.getElementById('reveal').onclick = function() { // handle click
var items = document.getElementsByTagName('li');
for( var i = 0; i < items.length; i++ ){ // for all list elements...
var tempclass = items[i].className;
// if the class is "hide", unhide
items[i].className = tempclass === 'hide' ? '' : tempclass;
}
}
Of course there are many other ways to do this more thoroughly -- and this one doesn't even slide. jQuery does make life a bit easier.
Here's the working example: http://jsfiddle.net/redler/jsQ47/
Here's with the slide down effect:
http://jsfiddle.net/deNzh/
That's what you're looking for, right?
you could assign the first ten < li >s a class like < li class="always_show">Stuff goes here< /li > and then make a script that hides all, shows the "always_show" class and waits for a button click to show the whole thing.
might look something like:
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(function(){
$("#listorama").hide();
});
$(function(){
$(".always_show").show();
});
$(function(){
$("#show_all").click(function(){
$("#listorama").show();
});
});
</script>
<ul id="listorama">
<li class="always_show"></li>
<li class="always_show"></li>
<li class="always_show"></li>
<li class="always_show"></li>
<li class="always_show"></li>
<li class="always_show"></li>
<li class="always_show"></li>
<li class="always_show"></li>
<li class="always_show"></li>
<li class="always_show"></li>
<li>stuff to hide first</li>
<li>stuff to hide first</li>
<li>stuff to hide first</li>
<li>stuff to hide first</li>
<li>stuff to hide first</li>
</ul>
<button id="show_all">Show All</button>
Hope this helps!
Andy
function toggleListDisplay (list, cap) {
cap = parseInt(cap);
if (cap == null || cap < 0) { return; }
var elements = $(list).children();
if ($(elements[cap]).css('display') == 'none') {
// means we need to expand the list
elements.each(function(ind, ele) {
if (ind >= cap) { $(ele).slideDown(); }
});
$('.slide').html('Slide Up');
} else {
// means we need to shorten the list
elements.each(function(ind, ele) {
if (ind >= cap) { $(ele).slideUp(); }
});
$('.slide').html('Slide Down');
}
}
$('.slide').click(function(){
toggleListDisplay('#tester', 10);
})
toggleListDisplay('#tester', 10);
JSFiddle: http://jsfiddle.net/WqxGf/7/
I don't know why the others feel like making such a simple task more complicated than it is, but here is a much easier, shorter, and simpler way of achieving this:
$("a").click(function() {
var ul = $("#myid");
ul.animate({"height": ul[0].scrollHeight}, 1000);
});
Example: http://jsfiddle.net/kbUhW/13/

JQuery - How to move a li to another position in the ul? (exchange 2 li's)

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>

Expand list with slideToggle

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})});
});

Categories