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/
Related
What I'm trying to do is essentially go through uls which are organized like
<ul class="some-ul">
<li class="some-li"></li>
<li></li>
<li></li>
<li class="some-li"></li>
</ul>
<ul class="some-ul">
<li class="some-li"></li>
<li></li>
<li></li>
<li></li>
</ul>
<ul class="some-ul">
<li class="some-li"></li>
<li class="some-li"></li>
<li class="some-li"></li>
<li class="some-li"></li>
</ul>
and do something with the lis of class some-li and something else with the lis that don't have that class. So, it would be equivalent to
$('ul.some-class li.some-class').each(function() {
// do something
});
$('ul.some-class li:not(.some-class)').each(function() {
// do something else
});
except I want to do it like
$('ul.some-class').each(function() {
// loop through the list elements of this list
});
but I don't know how to construct that inner loop. Is this possible, and if so, what tool should I using?
Within .each, this will be the current element of the iteration. You can then use $(this).find() to find elements within it:
$('ul.some-ul').each(function(i, ul) {
$(ul).find("li").each(function(j, li) {
// Now you can use $(ul) and $(li) to refer to the list and item
if ($(li).hasClass('some-li')) {
...
}
});
});
You can use hasClass and a CSS selector to get all immediate children (The <li>s).
$('ul.some-class > li').each(function() {
if ($(this).hasClass('some-class')) {
//Do something
} else {
//Do something else
}
});
Loop through all the <li> and use hasClass() to see if they fit the class you want or not and react accordingly
$('.some-ul').children().each(function(){
// "this" is current li
if ( $(this).hasClass('some-li') ){
$(this).doSomeClassThing();
} else {
$(this).doNoClassThing();
}
});
One pass through and you are done
The callback of the each call gets the index and the element as arguments.
This way you can
$('ul.some-class').each(function(i, elt) {
$(elt, 'li.some-class').each ...
});
https://api.jquery.com/jquery.each/
I have a list
<ul>
<li class="list_1">a</li>
<li class="list_2">b</li>
<li class="list_3">c</li>
<li class="list_4">d</li>
</ul>
This is in a carousel, so that the list items change position (1-2-3-4, 2-3-4-1, 3-4-1-2, 4-1-2-3,...)
How can I find out, using javascript, which item is in, let's say, second and third position?
In the beginning, the list_2 and list_3 are in second and third position, after one cycle, the list_3 and list_4 are in second and third position, etc.
How to find out what list is in those positions, while I cycle through? For starters I just need to see it displayed in console with console.log(), something like:
On 2nd place is list_3, and on third is list_4.
Tried with this but doesn't work:
var $list_items = $(this).find('ul li');
$list_items.each(function(i,j){
$(this).addClass('list_' + (i+1));
console.log($list_items.eq(2).attr('class'));
});
I'm using $(this) because my original lists are enclosed in a div, and originally lists had no class, so I added them.
One approach is to use map() and index() to create an array of the element's class-name and index, obviously this depends on what, precisely, you want to find; but your question is somewhat vague on the result you want:
function mapIndices() {
// iterate over the 'ul li' elements, forming a map:
return $('ul li').map(function() {
// returning the className (classes) of the element and its index amongst
// siblings:
return this.className + ': ' + $(this).index();
// converting to an Array:
}).get();
};
// this is just a simple trigger to move the elements,
// to demonstrate binding the function:
$('#change').on('click', function() {
var ul = $('ul');
ul.find('li:first-child').appendTo(ul);
console.log(mapIndices());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="change">advance positions</button>
<ul>
<li class="list_1">a</li>
<li class="list_2">b</li>
<li class="list_3">c</li>
<li class="list_4">d</li>
</ul>
If, however, you simply want to find out which element is in a specific position:
$('#change').on('click', function() {
var ul = $('ul');
ul.find('li:first-child').appendTo(ul);
// bear in mind that JavaScript has zero-based indexing,
// 2 is the index of third element, not the second:
console.log(ul.find('li').eq(2));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="change">advance positions</button>
<ul>
<li class="list_1">a</li>
<li class="list_2">b</li>
<li class="list_3">c</li>
<li class="list_4">d</li>
</ul>
References:
eq().
find().
get().
index().
map().
on().
Array manipulation:
var arr = $('li').get(); // http://api.jquery.com/get/
// var arr = ["aa","bb","cc","dd"]; // you can try also using this guy
function doIt(){
if(this.id==="next") arr.push( arr.shift() ); // send first to last
else arr.unshift( arr.pop() ); // send last to first
$('ul').html( arr );
}
$('#prev, #next').on('click', doIt);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="prev">PREV</button>
<button id="next">NEXT</button>
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>-----------</li>
</ul>
First give an id/class to the ul:
<ul id="mylist">
<li class="list_1">a</li>
<li class="list_2">b</li>
<li class="list_3">c</li>
<li class="list_4">d</li>
</ul>
Using jQuery to access the 'li' element at 2nd position:
var second_li = $('#mylist').find('li')[1]; // to access 2nd li use index 1
var second_li_class = $(second_li).attr('class'); // second_li_class will be equal to 'list_2'
var second_li_content = $(second_li).html(); // second_li_content will be equal to 'b'
I've read many tutorials and can't seem to get it right. Ok I know that the jquery click function works when you are doing something to the exact same element but how do you make it effect another and toggle back?
I have a menu and when I click on an item I want the background (body) to change to an image.
Example:
HTML
<body>
<ul class="menu">
<li class="menu-item"><a>item 1</a></li>
<li class="menu-item"><a>item 2</a></li>
<li class="menu-item"><a>item 3</a></li>
</ul>
</body>
JQUERY
$(".menu-item a").click(function () {
$(body).css('background', 'http://example.com/image.png'); <-- first menu item
$(body).css('background', 'http://example.com/image.png'); <-- second menu item
$(body).css('background', 'http://example.com/image.png'); <-- third menu item
});
You can use .index() - DEMO
$("a").on("click", function(e) {
e.preventDefault();
var i = $("li").index( $(this).parent() );
if ( i === 1 ) {
$('body').css('background', 'beige');
} else if ( i === 2 ) {
$('body').css('background', 'honeydew');
} else {
$('body').css('background', 'pink');
}
});
Does this seem about like what you're trying to do?
$(".menu-item a:nth-child(1)").click(function () { // first menu item
$(body).css('background', 'http://example.com/image.png');
});
$(".menu-item a:nth-child(2)").click(function () { // second menu item
$(body).css('background', 'http://example.com/image.png');
});
$(".menu-item a:nth-child(3)").click(function () { // third menu item
$(body).css('background', 'http://example.com/image.png');
});
I don't know what you are trying but I could give you hints.
$(".menu-item a") // is an array/jquery collection of all elements that match the selector
.click(function () { // binds the function now to the click event of every item found
$(this); // is now the currently clicked element
// you can now traversal with $(this) for example
$(this).siblings(); // will be a collection of all surrounding elements
$(this).next(); // is the next element after the current one, can be chained like:
$(this).next().next(); // but I wouldn't recomand
$(this).prev(); // same as next but prev
$(this).parent(); // selects the direct parent element, in your case the li element
$(this).children(); // would select the direct children of the current element
// and so on.... there are much more possibilities
// on every of this possibilities you can do your background change
$("some selector"); // is of course still possible
// i think you are trying to do this:
var menuItems = $(".menu-item a");
menuItems.eq(0).css("background", "url to bg 1");
menuItems.eq(1).css("background", "url to bg 2");
menuItems.eq(2).css("background", "url to bg 3");
})
Look at the Traversing section of the jQuery docu. I would also always recommend to look what jQuery is actually doing. Many people hide behind jQuerys api and have no idea whats happening. This results into many misunderstandings.
You may try something like this
HTML:
<body>
<ul class="menu">
<li class="menu-item"><a name="blue" href="#">item 1</a></li>
<li class="menu-item"><a name="red" href="#">item 2</a></li>
<li class="menu-item"><a name="orange" href="#">item 3</a></li>
</ul>
</body>
CSS:
.red {
background:red;
}
.blue {
background:blue;
}
.orange {
background:orange;
}
Jquery:
$('.menu').on('click', 'a', function () {
var bgColor = $(this).attr('name');
$('body').removeClass().addClass(bgColor);
return false;
});
DEMO
The way I suggest going about this is to grab the position of the element that has been clicked. You can do this by using jQuery's index() function as other posters have suggested. Remember this will give you a zero-based index of the position which means that the position counting starts at 0 as opposed to 1.
Based on the item that has been clicked, you assign a CSS class to the target item which is the body element based on the sample code you provided.
Also, I noticed that your JS comments are still invalid even they were edited. Single line comments in JS use a double forward slash, // whereas multiline comments begin with /* and are closed by */.
This is my solution: http://jsfiddle.net/tgZUK/.
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
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>