I have nested lists in my HTML page, these lists are managed by a jQuery code which give to the user the interaction of adding rows and children to the list nodes. Every list can contain a div used to add a new list as child.
My problem is I would like to add a dynamic limiter to the deep of the elements I can create:
<ul>
<li>
<ul>
<li><div class="add-child"></div></li>
<li><div class="add-child"></div></li>
<li><div class="add-row"></div></li>
</ul>
</li>
<li><div class="add-child"></div></li>
<li><div class="add-child"></div></li>
<li><div class="add-row"></div></li>
</ul>
The deep could change in the future, I know I can simply use a static selector like this if I want to work with a max of 3 levels of deepness:
$('li li li .add-child').remove();
But I would like a dynamic solution to set the deep via PHP and then limit it via jQuery, how could be my approach to this?
$('.add-child')
.filter(function(){
return $(this).parents('li').length > 2;
})
.remove();
I know, you said you don't need a plugin, but I couldn't resist :D
$.fn.filterIfHasNParents = function(n, selector){
var depth = n || 1;
return $(this).filter(function(){
return $(this).parents(selector || '').length > depth - 1;
});
}
And then use it as :
$('.add-child').filterIfHasNParents(3, 'li').remove();
You mean something like this?
$( '.add-child' ).each( function() {
if( $( this ).parents( 'li' ).length > someDepthSetByPHP )
{
$( this ).remove();
}
} );
jsfiddle example
Related
I think it's a lot easier to understand what i am trying to achieve just by posting the code. But the idea is. i have about 8 li items, but after 3, i would like to create a new li item called "more" and the remaining 5 items should be moved into a new ul that will act as a submenu.
here's the html
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
<li>item5</li>
</ul>
here's the javascript
$('.ow_main_menu').each(function(){
var max = 3
if ($(this).find('li').length > max) {
$(this).find('li:gt('+max+')').hide().end().append('<li class="show_more">More</li>');
$('.show_more').hover( function(){
/* stuck */
});
};
});
Here's how it should be like
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li class="show_more">More
<ul>
<li>item4</li>
<li>item5</li>
</ul>
</li>
</ul>
The show more part i got it working, but i have no idea on how to wrap the rest of the items.
One approach is the following (though it still feels a little too clunky):
// using 'on()' to delegate the click-event handling to a 'ul' element
// that exists in the DOM, that becomes an ancestor to the created
// elements:
$('ul').on('click', 'li.more', function(e){
$(this).find('ul').toggle();
});
// select all 'li' elements, retain only the 3rd (JavaScript's indexing is
// zero-based:
$('li').eq(2)
// get all the subsequent siblings:
.nextAll()
// wrap them all together within the supplied HTML:
.wrapAll('<li class="more">Read more<ul></ul></li>')
// find the ancestor 'ul' (to the 'li' elements returned by 'wrapAll()'):
.closest('ul')
// hide that 'ul':
.hide();
JS Fiddle demo.
References:
click().
eq().
find().
nextAll().
on().
toggle().
wrapAll().
This is how you can do it:
var max = 3;
$('ul').children('li:gt(' + (max - 1) + ')') // find all LI after max
.wrapAll('<ul>').parent() // wrap with UL and get it
.wrap('<li class="show_more">More</li>'); // wrap UL with LI.show_more
Demo: http://jsfiddle.net/n57g3/1/
Currently working on the Squarespace.com platform and I'd like to re-sort a dynamic Blog Category index that defaults to alphabetical sorting. This is how Squarespace generates the code:
<div id="moduleContentWrapper11663355" class="widget-wrapper widget-type-journalarchive">
<div id="moduleContent11663355">
<ul class="archive-item-list-pt">
<li>
Category One
<span class="entry-count">(1)</span>
</li>
<li>
Category Two
<span class="entry-count">(1)</span>
</li>
<li>
Category Three
<span class="entry-count">(1)</span>
</li>
</ul>
</div>
</div>
Is it possible to re-sort the entries using Jquery, or worse case, can I append a unique CSS class to each <li> so I can manipulate each one using CSS?
Thanks!
the dom is really nothing but a complicated collection... you can use jquery to sort the li like an array.
var mylist = $('#moduleContent11663355 > ul');
var listitems = mylist.children('li').get();
listitems.sort(function(a, b) {
var compA = $(a).text().toUpperCase();
var compB = $(b).text().toUpperCase();
return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
})
$.each(listitems, function(idx, itm) { mylist.append(itm); });
thanks to http://www.onemoretake.com/2009/02/25/sorting-elements-with-jquery/
var i = 1;
$('.archive-item-list-pt li').each(function(item) {
$(item).addClass('myClass'+i);
});
$('.archive-item-list-pt li').each(function(i,j) {
$(this).addClass('yourClass'+i);
});
here is the fiddle http://jsfiddle.net/h2gfT/7/
update
$('.archive-item-list-pt li').each(function(i,j) {
var cls=$(this).children("a").text().toLowerCase();
var idx = cls.replace(' ','-');
$(this).addClass(idx);
});
here is the fiddle http://jsfiddle.net/h2gfT/9/
one with jquery chaining hotness
$('.archive-item-list-pt li').each(function(i,j) {
var cls=$(this).children("a").text().toLowerCase().replace(' ','-');
$(this).addClass(cls);
});
http://jsfiddle.net/h2gfT/11/
Sort items in place based in the arbitrary key function
http://blog.mirotin.net/125/jquery-sortitems
Sorting the entries with jQuery can be done in a couple diffrent ways, but if you just want to append CSS to each of them you could do that in two different ways.
$('li').each(function(l) { $(this).attr('class', '<insertnameofcssclasshere>') })
or
$('li').each(function(l) { $(this).css(<insertcssstuff here>) })
Of course, these would apply it to all li elements on your page. You would want to use more specific or contained selectors if you want to affect just some of them.
I have an unordered list comprised of little bits of HTML (images, styled text, forms, etc.). The number of items in the list is a variable between 1 and 10. How can I create a pagination system such that all the list items are shown in one DIV if there are 5 or less items, and another DIV is created and filled with the overflow if there are more than 5 items?
For example here is a list with an arbitrary number of elements (in this case, seven):
<ul>
<li><img src="photo.jpg" /></li>
<li><strong>TEXT TEXT TEXT</strong></li>
<li><img src="another_photo.jpg" /></li>
<li><strong>MORE TEXT TEXT TEXT</strong></li>
<li>Say Hello!</li>
<li>MORE STUFF</li>
<li>YET EVEN MORE STUFF</li>
</ul>
And this would be the resulting DIVs
<div id="first_div">
<ul>
<li><img src="photo.jpg" /></li>
<li><strong>TEXT TEXT TEXT</strong></li>
<li><img src="another_photo.jpg" /></li>
<li><strong>MORE TEXT TEXT TEXT</strong></li>
<li>Say Hello!</li>
</ul>
</div>
<div id="second_div">
<ul>
<li>MORE STUFF</li>
<li>YET EVEN MORE STUFF</li>
</ul>
</div>
I think this will get you what you want in pretty short order. It ensures that the two new DIVs land in the DOM where the original UL used to be. It also uses pure jQ selector power rather than loops and counters.
Live Demo: http://jsfiddle.net/JAAulde/3cRZw/1/
Code:
var UL = $( 'ul' ),
upperLIs = UL.find( 'li:gt(4)' ), //get list of LIs above index 4 (above 5th)
DIV1 = $( '<div>' ).attr( 'id', 'first_div' ); //we will definitely need this first DIV
//Get the first DIV into the DOM right before the UL before any movement of UL
//Ensure same DOM placement as we started with
UL.before( DIV1 );
//Check for LIs above index 4
if( upperLIs.length )
{
//Add those LIs to a new UL
//which itself is added to a new DIV
//which itself is added after DIV1
DIV1.after(
$( '<div>' )
.attr( 'id', 'second_div' )
.append(
$( '<ul>' )
.append( upperLIs )
)
);
}
//Move the original UL to DIV1 with it's remaining 5 LIs
DIV1.append( UL );
Edit: edited code to add explanatory comments
Wrap the <ul> in a div. Then grab the last 5 <li> and append them to a new <ul> inside a new <div>:
var ul = $("#myList").wrap($("<div>").attr("id", "first_div"));
$("<div><ul>").attr("id", "second_div").insertAfter("#first_div")
.append(ul.find("li:gt(4)"));
Probably a bit verbose bit this should do it (untested):
$(function() {
var threshold = 5;
// get the original list
var $ul = $("ul");
// create the first container
var $div = $("<div id='first_div'><ul /></div>").appendTo('body');
$("li", $ul).each(function(i) {
if(i < threshold) {
$("ul", $div).append($(this));
}
else {
$overflowDiv = $("#second_div");
// create the second container if it doesn't already exists
if(!$overflowDiv.length) {
var $overflowDiv = $("<div id='second_div'><ul /></div>").appendTo('body');
}
$("ul", $overflowDiv).append($(this));
}
});
// remove the (now empty) list
$ul.remove();
});
var lis=$('ul li');
var divuid=1;
var i=0;
while(lis.length>i){
var lisPart=lis.slice(i,i+4);
i+=4;
$('<div id="div'+(divuid++)+'"></div>').append(lisPart).appendTo($('#my_container'));
}
$('ul li').remove();
shot in the dark, haven't tested it yet... something like this though?
I'm using jQuery UI's sortable for my UL list. Each time the user sorts the list, I want each li element to update it's "position" attribute to it's position in the list.
<ul>
<li position="1">a</li>
<li position="2">b</li>
<li position="3">c</li>
</ul>
So when a user swaps c with a, the position will also update. I tried to use .each but it seems that javascript doesn't follow the order of how the LI elements are displayed but the order of the element's creation.
As mentioned in another answer, using update is all you need:
$(function() {
var $sortable = $('ul').sortable({
update: function(event, ui) {
var counter = 1;
$('li', $sortable).each(function() {
$(this).attr('position', counter);
counter++;
});
}
});
});
Example link
Have you tried :eq selector or index method? Provided you know which li element you're trying to find the position of you could find the position like so:
<ul>
<li id="c">c</li>
<li id="b">b</li>
<li id="a">a</li>
</ul>
var position = $('li#b').index();
You'll want to take advantage of the Sortable "update" event:
$( "ul" ).sortable({
update: function(event, ui) {
var order = $(this).sortable('serialize');
console.info(order);
}
});
You can then use the "serialize" method to pull the updated order of items. One requirement for this to work is that the IDs of each list item contain an underscore, so you'd want to update your HTML to:
<ul>
<li id="position_1">a</li>
<li id="position_2">b</li>
<li id="position_3">c</li>
</ul>
How do I modify the style of the li element using DOM?
<div id="tabbed-boosts">
<ul>
<li>test1</li>
<li>test2</li>
<li>test3</li>
</ul>
</div>
getElementById('tabbed-boosts').childNodes will get me to the UL, how do I modify the LI?
Also needs to work in IE6...
var lis = document.getElementById( 'tabbed-boosts' ).getElementsByTagName( 'li' );
for ( var i = 0; i < lis.length; i++ )
{
lis[i].style.backgroundColor = '#' + Math.round( Math.random() * 0xFFFFFF ).toString( 16 );
}
The issue with using document.getElementById( 'tabbed-boosts' ).getElementsByTagName( 'li' ) will show up if you start using nested lists. Using childNodes property will give you access to the direct children of that particular ul element. For example
<ul id='tabbed-boosts'>
<li>...</li>
<li>
<ul>
<li> ... </li>
</ul>
</li>
<li>... </li>
</ul>
using getElementsByTag will return ALL the 'li' elements within tabbed-boosts sub-tree, where childNodes will only return the first level 'li' elements. In the example above you'd receive a collection of 4 elements using getElementById, including the nested LI whereas you would only receive a collection of 3 li elements using myUl.childNodes (shown below)
var myUl = document.getElementById('tabbed-boosts');
var myLi = myUl.childNodes;
for(var i = 0; i<myLi.length; i++)
{
myLi[i].style....;
// do whatever you want to the li items;
}