Jquery Exact Count of a li elemnt - javascript

I'm trying to create an element(ul) that the width can be changed depending on the number of element(li) contained in this (ul).
I used jquery to get this done but i don't get the right result as i'm making an error and i don't how to fix it.
here is my jquery code:
jQuery('ul.class').each(function(){
var n = jQuery('ul.class li').length;
console.log(n);
jQuery(this).css('width',n*(jQuery('ul.class li').width() + 10));
console.log(n*jQuery('ul.class li').width());
});
10 in this code is the border or each element.
The issue is in this part var n = jQuery('ul.class li').length and i don't know of to get the exact count of each li contained in a ul.
li has a width 150px

jQuery('ul.class').each(function(){
var n = jQuery(this).find('li').length;
alert(n);
jQuery(this).css('width',n*(jQuery(this).find('li').width() + 10));
alert(n*jQuery(this).find('li').width());
});
Demo:
http://jsfiddle.net/84Bv6/1/

Related

Take 3 random items from a ul and append to another list with random fadeIn and fadeOut

So I have got so far with this function, but now I am struggling with one issue.
I have made a fiddle here: http://jsfiddle.net/lharby/WhUJq/3/
I have a ul which is hidden the function takes 3 li items from the ul and appends them to a visible ul.
What I want to do is to have a nice fadeIn and fadeOut function on these items. And I was hoping that the fade could be staggered over each li.
This is the function:
function rndSlider() {
var $show = 3, // Number of items to show
$elemLength = $('.slider li').length, // Total items
$firstPart = '<li><img src="/img/slider/0',
$lastPart = '.jpg" /></li>',
array = [], // array with all available numbers
rnd, value, i,
$wrapper = $('.slider-clone');
$('.slider-clone li').remove();
for (i = 0; i < $elemLength; i++) {
array[i] = i + 1;
}
for (i = 0; i < $show; i++) { // pick numbers
rnd = Math.floor(Math.random() * array.length);
value = array.splice(rnd,1)[0]; // remove the selected number from the array and get it in another variable
$wrapper.append($firstPart + value + $lastPart);
}
}
I wondered if I needed an each function on the
$('.slider-clone li').remove();
Applied to each li element (I have a fadeIn function working on the fiddle, but not the fadeOut).
And then a fade in on the
$wrapper.append($firstPart + value + $lastPart);
But I cannot seem to get anything to work, when I apply one of these, it seems to upset the main function from running.
TIA
Hmm.. well thats awkward.. When i posted this.. it worked well.. I think this issue might have to do with the fadeIn and fadeOut being done async.. The problem here is that when the child images are created the fadeOut effect-callback removes them..
$(this).children().remove();
I've updated your fiddle:
http://jsfiddle.net/WhUJq/15/
So if i understand you correctly, the problem is the fadeOut() effect?
replace:
$('.slider-clone li').each(function(){
$(this).fadeOut(400);
});
with the following code to solve that issue:
$wrapper.fadeOut('slow', function(){ $(this).children().remove(); });

dynamic calculation of li height

I have the following code
The issue is that currently I am hardcoding the height when hovered to be 300, how do I do it such that it gets the height based on the number of tag it has, so say there are 6 and each li is 50px height so then the height is 300.
I am talking about this line specifically:
$(this).stop().animate({"height":"300px"},1000).addClass("dropped");
Also how do I make it such that when it's already expanded, and I click on it again it animates back un-expanded
Get the height of the ul and then set the #expandable animating height.
$("#expandable").click(function() {
var ulHeight = $(this).children("ul").height() + 50;
$(this).stop().animate({"height":ulHeight + "px"},1000).addClass("dropped");
});
DEMO
try this code
$("#expandable").hover(function() {
var _aH = (parseInt($(this).find('ul li').length)+1)*50
$(this).stop().animate({"height":_aH+"px"},1000).addClass("dropped");
}, function() {
$(this).stop().animate({"height":"50px"},1000).removeClass("dropped");
});
see fiddle
basically, you need to calculate number of lis in your ul and then findout the total height.
Code assumes 50px to be the height of the li, you can make that one also generic, by grabbing the height of the li.
Firstly, you need to close the your ul using </ul> not </nav>
Secondly, to make it dynamic instead of harcode height, you need to calculate the total height of your list. Here is how you do it:
var sum = 50;
$('#expandable').find('li').each(function() {
sum += $(this).height();
});
$("#expandable").click(function() {
$(this).stop().animate({"height": sum},1000).addClass("dropped");
});
Working Demo
You can get the height of the ul like that with jQuery:
$('#expandable').find('ul').height();
...then just add the height of the span and you get the computed height for the animation :)
As for your other problem: Just check for your dropped class and animate it back if it is there:
$("#expandable").click(function() {
var ulHeight = $('#expandable').find('ul').height();
var spanHeight = $('span').height();
var computedHeight = (ulHeight + spanHeight);
if( $(this).hasClass('dropped') ) {
$(this).stop().animate({"height": (spanHeight + "px") },1000).removeClass("dropped");
return false;
}
$(this).stop().animate({"height": (computedHeight + "px") },1000).addClass("dropped");
});
See my Fiddle:
Fiddle

jquery animate ul by list item

I have a ul that I want to center vertically to the vertical center of another element based upon the li that a user clicks. I have some code worked up here:
http://jsfiddle.net/XxmAT/1/
But it is unfortunately not behaving how I would like it to, I know my math is off, so any help would be much appreciated!
I think this one is prettier:
http://jsfiddle.net/XxmAT/33/
Usually it is best to think of the logic first, and start making variables after. Because of the cluster of variables, it was hard to understand what you meant with all the code. The click function just got a lot simpeler, and it is easier to understand what I am subtracting from which number, to get the desired result...
Sidenote: The - 180 at the end is probably the strange (and enormous) margin.
here you go. Got the height of the li and multiplied it to account for the height of the space between li and then multiplied by the index that was clicked.
http://jsfiddle.net/XxmAT/36/
var u_menu = $("#menu-main-menu").position().top;
var z_menu = $("#menu-main-menu").height();
var y = $("#box1").offset().top;
var z = $('#box1').height();
var c_menu = (z_menu / 2) ;
$("#menu-main-menu").css('top', - c_menu);
$('ul#menu-main-menu li').click(function (e) {
// this is the dom element clicked
var index = $('li').index(this);
var x = $('li').height() * 2;
var offset_li = (u_menu + y) / index ;
$('ul#menu-main-menu').animate({top: -(x*index)}, "slow")
});​

Split ul to more ul's with jQuery

I have made a script with jQuery. The script split a list of li's, to more ul's. When the list is moer than 10 li items the list must be split in more ul's.
I have made the script in this post.
But the script is not working. What I did wrong here.
The script is for a submenu in the navigation. When the navigation li items are more than 4 than the ul of li items must be splitted in two ul's. How can I fix this script. Thanks!
submenu();
function submenu() {
$(".submenu").each(function () {
if($("li", this).length > 4){
$(this).closest(".submenu").addClass("width-2")
var submenu = $(this).closest(".submenu");
var $bigList = $(this), group;
while((group = $bigList.find('li:lt(8)').remove()).length) {
$('<ul/>').append(group).appendTo(submenu);
}
}
if($("li", this).length > 10){
$(this).closest(".submenu").addClass("width-3")
}
});
}
I'm not entirely sure I understand what you're trying to do, but this code will split each submenu UL into more submenus of the specified size while keeping all items in the original DOM order:
function splitSubmenu(maxNumItems) {
$(".submenu").each(function () {
// get all child li tags
var list$ = $(this).children("li");
var num, nextAfter$, after$ = $(this);
// as long as the current list it too long, loop
while (list$.length > maxNumItems) {
// decide how many to remove this iteration
num = Math.min(maxNumItems, list$.length - maxNumItems);
// create new UL tag, append num items to it
// and insert it into the DOM
nextAfter$ = $('<ul class="submenu">')
.append(list$.slice(maxNumItems, maxNumItems + num))
.insertAfter(after$);
// update insertion point for next loop iteration
after$ = nextAfter$;
// remove the items we just took out from the current jQuery object
list$ = list$.filter(function(index) {
return(index < maxNumItems || index >= 2 * maxNumItems);
});
}
});
}
splitSubmenu(4);
You can see it work here: http://jsfiddle.net/jfriend00/VMjvQ/.
I did not understand what you were trying to do with the additional classes so that part is not included.

Equalize two ULs by height

I have a case where I'm provided with one UL, and an unknown number of LIs. I'm looking to use JS to split the LIs into 2 ULs (I'm using jQuery). I'm able to split the ULs evenly by number of LIs, but I'd like to split it based on the height of each LI as well, so that both ULs are close to the same height.
Any help with this would be appreciated, I don't feel like I'm getting anywhere with the approach I started with.
Thanks.
EDIT: JS code I currently have. The HTML is just a straight UL/LI, each LI can be of varying height.
var $sections = $('div.subsection');
$sections.each(function(){
var $section = $(this);
var $list = $section.children('ul');
var $items = $list.children('li');
var itemCount = $items.size();
var leftover = itemCount % 2;
var itemsPerColumn = Math.floor(itemCount / 2);
var $newList = $('<ul />');
$items.each(function(){
var $this = $(this);
var index = $items.index($this);
if (index >= (itemsPerColumn + leftover)) {
$this.remove().appendTo($newList);
}
});
$list.after($newList);
_equalizeListHeights();
function _equalizeListHeights(){
var listHeight = $list.height();
var newListHeight = $newList.height();
if (listHeight > newListHeight){
var $lastItem = $list.children('li:last');
var lastItemHeight = $lastItem.height();
if (listHeight - lastItemHeight > newListHeight + lastItemHeight){
$lastItem.remove().prependTo($newList);
_equalizeListHeights();
}
}
}
});
You can do it via CSS:
.double_column_list li {float: left; width: 50%;}
<ul class="double_column_list">
<li>Awesome Stuff Awesome Stuff Awesome Stuff Awesome Stuff Awesome Stuff</li>
<li>Awesome Stuff</li>
<li>Awesome Stuff</li>
<li>Awesome Stuff</li>
</ul>
To get 3 column, set width: 33.333%, 4 column width: 25% and so on.
Of course, if you keep increasing the height of one li to a point where rest of the lis can't match, this would look bad. But then, that issue cannot be fixed through JS either.
http://jsfiddle.net/rQJQb/
Update:
As pointed out by commenters, if list items are not sorted by height (i.e. height of any one list item in the middle may be bigger/smaller than the ones preceding it), a sorting is needed: http://jsfiddle.net/rQJQb/2/
I think I can at least see the approach here:
Calculate the total height of all the list items (total), and store all the individual heights
Calculate the height of one list (total / 2)
Determine an algorithm to sum a set of heights to come as as possible to total / 2, without exceeding it.
Put the elements with these heights into the first list, and put the rest into the second
Step 3 is the tricky bit. It's related to the Subset Sum Problem.
EDIT
Here's a brute-force algorithm which solves your problem. It doesn't run on window.resize, because that would be silly. If you want to see it change, resize the result window, then push run.
//Sum a jQuery wrapped array
$.fn.sum = function() {
var total = 0;
this.each(function() { total += this; });
return total;
};
//Mask elements with a bitmask
$.fn.mask = function(mask) {
return this.filter(function(i) {
return (mask >> i) & 1;
})
}
//Get the sizes, and sneakily return a jQuery object
var sizes = $('.first li').map(function() { return $(this).outerHeight() });
var total = sizes.sum();
var maxTotal = total / 2;
var best = {
total: 0,
mask: 0
}
for (var subsetMask = 1; subsetMask < (1 << sizes.length); subsetMask++) {
//Sum all the heights in this subset
var subsetTotal = sizes.mask(subsetMask).sum();
//New optimal solution?
if (subsetTotal > best.total && subsetTotal <= maxTotal) {
best = {
total: subsetTotal,
mask: subsetMask
};
}
}
$('.first li').mask(best.mask).appendTo('.second');
The CS problem you are trying to solve
You should look into the Backpack Problem. The items to be 'inserted into the backpack' will be the LIs. Each LI will have a weight and value equivalent to its height. The backpack capacity should be half the sum of all the LI heights. Run an algorithm to solve the backpack problem and your LIs will be divided into two sets with heights as you've described.
Intuitive explanation
The backpack algorithm finds a subset of items such that the value is as large as possible, but the weight doesn't exceed the backpack capacity. But our weight and value of each LI is its height, and the backpack capacity is half the total height of all LIs combined.
So essentially what it will give us is a set of all LIs such that the height is as high as possible without exceeding 1/2 the total height. In the case where you should end up with two equal-height sets of LIs, this will be one of the sets. In the case where you should end up with two sets of LIs with different heights, the backpack problem solution will return the set with a smaller height (and the remaining, unchosen LIs would be the second set).
Solution
Try the code used here: http://rosettacode.org/wiki/Knapsack_problem/Bounded#JavaScript
Or if you want to roll your own (not recommended - why bother?): http://en.wikipedia.org/wiki/Knapsack_problem#Unbounded_knapsack_problem
$("ul.first li").each(function() {
if ($("ul.first").outerHeight() > $("ul.second").outerHeight()) {
$(this).appendTo($("ul.second"));
}
});
Use this jQuery code.

Categories