Solved

UL and Nested UL Height

Posted on 2010-11-22
8
1,325 Views
Last Modified: 2012-05-10
All,

Kindly refer to the attached jpg with the listed problem included and review the script of HTML and jquery in order to investigate the root cause.

Basically, my design is to enable the expand/collapse of every UL via the DIV and IMG elements.
It's working properly if I do not have any nested UL elements within.

So now my question how to make it works with the current script attached when introduce the nested UL element in. I'm looking and trying not to make use of any CSS.
I'm thinking that need to address the height issue of nested lists in the jquery instead.

Please advice. Thanks.

Attached of the outcome of the script together with problem listed
<script type="text/javascript">
$(document).ready(function () { 
 // Find the heights of all the ul elements to be 
 // used  later during toggle

 ulHeights = [];
 var toggleElements = $('.toggle');
 //map's id attribute value as key to ul css height
 ulHeights = {}; 

 toggleElements.each(function () {
  var ul = $(this).parent().find('ul');
  var id = ul.attr('id');
  if (!ulHeights.hasOwnProperty(id)) {
   ulHeights[id] = ul.height();
   //ul.height(0);
  }
 });
	
 var animationDuration = 500;
 function toggleOnClick() {
  var ul = $(this).parent().find('ul')
  var img = $(this).parent().find('img')

  if (ul.height() == 0) { //expand
   ul.children('li').children('div').children('ul')
    .each(function(i) {
    $(this).attr('src', 'arrow_down.gif');
    $(this).animate(
     {height:ulHeights[$(this).attr('id')]}, 
     {duration: animationDuration});
   });
			
   img.attr('src', 'arrow_down.gif');
   ul.animate(
    {height: ulHeights[ul.attr('id')]}, 
    {duration: animationDuration});
  }
  else { //collapse
   ul.children('li').children('div').children('ul')
    .each(function(i) {
    $(this).attr('src', 'arrow_right.gif');
    $(this).animate({height: 0}, 
     {duration: animationDuration}); 
    });

   img.attr('src', 'arrow_right.gif');
   ul.animate({height: 0}, {duration: animationDuration});
  }
 }
 toggleElements.click(toggleOnClick);
});
</script>

Open in new window

<DIV style="PADDING-TOP: 10px">
 <IMG class=toggle src="/goldarrow_right.gif"> 
 <A style="COLOR: #a29061" class="generic-header2 
  toggle plain" href="" name=section1>Section 1</A> 
 <UL style="MARGIN: 0px; OVERFLOW: hidden" id=0>
  <LI>
   <DIV style="PADDING-TOP: 10px">
    <IMG class=toggle src="/goldarrow_right.gif"> 
    <A style="COLOR:#a29061" class="generic-header2 
     toggle plain" href="" name=section2>
     Sub Section  1.0</A> 
    <UL style="MARGIN: 0px; OVERFLOW: hidden" id=1>
      <LI><A class=link href="" target=_blank>
       Content 1</A> </LI> 
      <LI><A class=link href="" target=_blank>
       Content 2</A> </LI>
    </UL>
   </DIV>
  </LI>
  <LI><A class=link 
    href="" 
    target=_blank>ABC</A> 
  </LI>
    <LI><A class=link 
    href="" 
    target=_blank>DEF</A> 
    </LI>
 </UL>
</DIV>

Open in new window

0
Comment
Question by:wintersun
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
8 Comments
 
LVL 18

Expert Comment

by:Sudaraka Wijesinghe
ID: 34195061
From what I understand your problem is when you collapse and expand the list using the top most toggle IMG, the items ABC and DEF runs out of view port.

This happens because of one of the element selections in your code
var ul = $(this).parent().find('ul')

Open in new window

Here you are selecting all the UL elements inside the main DIV, your have 2, the main UL which contains all the list items, and the UL with in that main UL which contains ABC and DEF.
so the value get assigned to your variable ul is an array of 2 elements.

Therefor, in the code (line 35 in the code you posted)
ul.animate(
    {height: ulHeights[ul.attr('id')]}, 
    {duration: animationDuration});

Open in new window

it animates the two UL elements separately, and I believe you only need to animate the first of them.

So you can change it to only animate the first UL like this:
$(ul[0]).animate(
    {height: ulHeights[ul.attr('id')]}, 
    {duration: animationDuration});

Open in new window


Although this will work for your current HTML structure, if you nest more UL into this this might break again. So you will need to use this method and come up with an algorithm if you are planing to do that.

P.S.
Digging in to this code might also help you.
http://www.jstree.com/demo
0
 

Author Comment

by:wintersun
ID: 34195315
Yes, you're correct here as the root cause is from the line below:-
var ul = $(this).parent().find('ul');

I've fixed the code by changing to use 'children' instead and it resolves my issue:-
var ul = $(this).parent().children('ul');

BTW, I've a another question about to apply css on LI which contains nested UL (in this example is LI > DIV > UL -> Sub Section 1.0 has children of Content 1 and Content 2)

// reset nested list settings
$('ul > li:has(div > ul)').each(function ()  {
  $(this).css('list-style-image', '/goldarrow_right.gif', false)})');
  $(this).addClass('toggle');
  $(this).click(toggleOnClick);
})

After the above code executed,

<LI> -> THIS <LI> CHANGED AS HAS CHILDREN OF DIV > UL
   <DIV style="PADDING-TOP: 10px">
    <IMG class=toggle src="/goldarrow_right.gif">
    <A style="COLOR:#a29061" class="generic-header2
     toggle plain" href="" name=section2>
     Sub Section  1.0</A>
    <UL style="MARGIN: 0px; OVERFLOW: hidden" id=1>
      <LI><A class=link href="" target=_blank> -> BUT THIS <LI>  IS CHANGED AS WELL AS NOT MY INTENTION, DO YOU KNOW WHY
       Content 1</A> </LI>
      <LI><A class=link href="" target=_blank> -> BUT THIS <LI>  IS CHANGED AS WELL AS NOT MY INTENTION, DO YOU KNOW WHY
       Content 2</A> </LI>
    </UL>
   </DIV>
  </LI>
0
 
LVL 18

Expert Comment

by:Sudaraka Wijesinghe
ID: 34195632
I don't see any problem with that piece of code except for the syntax error on css line:

// reset nested list settings
$('ul > li:has(div > ul)').each(function ()  {
  $(this).css('list-style-image', '/goldarrow_right.gif', false)})'); // <-- Syntax error here
  $(this).addClass('toggle');
  $(this).click(toggleOnClick);
})

// Should be

// reset nested list settings
$('ul > li:has(div > ul)').each(function ()  {
  $(this).css('list-style-image', '/goldarrow_right.gif');
  $(this).addClass('toggle');
  $(this).click(toggleOnClick);
})

Open in new window

0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:wintersun
ID: 34196223
I can't make it works if follow the code. Anyway, I've edit the way how I want it to render by placing an <IMG> and set <LI> that has <DIV > UL> .css('list-style-type', 'none').

But now I encountered another issue of the extra area on Main <UL> when the nested lists is collapse.
See attached "UL-LI-UL_collapse_blank_area.jpg".

Thanks.

Attach of the collapse issue
<DIV style="PADDING-TOP: 10px">
 <IMG class=toggle src="/plus.gif"> 
 <A style="COLOR: #a29061" class="generic-header2 
  toggle plain" href="">Main A</A> 
 <UL style="MARGIN: 0px; OVERFLOW: hidden" id=0>
  <LI>
   <DIV style="PADDING-TOP: 10px">
    <IMG class=toggle src="/plus.gif"> 
    <A style="COLOR:#a29061" class="generic-header2 
     toggle plain" href="">
     Sub A1</A> 
    <UL style="MARGIN: 0px; OVERFLOW: hidden" id=1>
      <LI><A class=link href="" target=_blank>
       Sub A1-1</A> </LI> 
      <LI><A class=link href="" target=_blank>
       Sub A1-2</A> </LI>
    </UL>
   </DIV>
  </LI>
  <LI>
   <DIV style="PADDING-TOP: 10px">
    <IMG class=toggle src="/plus.gif"> 
    <A style="COLOR:#a29061" class="generic-header2 
     toggle plain" href="">
     Sub A2</A> 
    <UL style="MARGIN: 0px; OVERFLOW: hidden" id=2>
      <LI><A class=link href="" target=_blank>
       Sub A2-1</A> </LI> 
      <LI><A class=link href="" target=_blank>
       Sub A2-2</A> </LI>
    </UL>
   </DIV>
  </LI>
  <LI><A class=link href="" target=_blank>Content A1</A></LI>
  <LI><A class=link href="" target=_blank>Content A2</A></LI>
 </UL>
</DIV>
<DIV style="PADDING-TOP: 10px">
 <IMG class=toggle src="/plus.gif"> 
 <A style="COLOR: #a29061" class="generic-header2 
  toggle plain" href="">Main B</A>
 <UL style="MARGIN: 0px; OVERFLOW: hidden" id=3>
 <LI><A class=link href="" target=_blank>Content B</A></LI></UL></DIV>

Open in new window

0
 

Author Comment

by:wintersun
ID: 34196275

<script type="text/javascript">
$(document).ready(function () {
		
 //Find the heights of all the ul elements to be 
 // used later during toggle
 ulHeights = [];
 var toggleElements = $('.toggle');
 //map's id attribute value as key to ul css height
 ulHeights = {}; 

 toggleElements.each(function () {
  var ul = $(this).parent().find('ul');
  var id = ul.attr('id');
  if (!ulHeights.hasOwnProperty(id)) {
   ulHeights[id] = ul.height();
  }
 });	

 var animationDuration = 500;
 function toggleOnClick() {
  var ul = $(this).parent().children('ul');
  var img = $(this).parent().children('img');

  ul.children('li').children('div').children('ul')
    .each(function() {
   $(this).parent().children('img').attr('src','/plus.gif');
   $(this).animate({height: 0}, {duration: 0});
  });  

  if (ul.height() == 0) { 
    img.attr('src', 'minus.gif');	
    ul.animate({height: ulHeights[ul.attr('id')]}, 
      {duration: animationDuration});
  } else {
    img.attr('src', 'plus.gif');	
    ul.animate({height: 0}, {duration: animationDuration});
  }
 }
 toggleElements.click(toggleOnClick);

 // reset nested list settings
 $('ul > li:has(div > ul)').css('list-style-type', 'none');

 $('ul > li > div').animate({marginLeft: '-15px'});
 
 $('ul').height(0);	
				
});
</script>

Open in new window

0
 
LVL 18

Accepted Solution

by:
Sudaraka Wijesinghe earned 500 total points
ID: 34196456
Gap is caused by the fixed height of the UL. Try setting it to auto (or to the desired height) after the animation is completed.

<script type="text/javascript">
$(document).ready(function () {
                
 //Find the heights of all the ul elements to be 
 // used later during toggle
 ulHeights = [];
 var toggleElements = $('.toggle');
 //map's id attribute value as key to ul css height
 ulHeights = {}; 

 toggleElements.each(function () {
  var ul = $(this).parent().find('ul');
  var id = ul.attr('id');
  if (!ulHeights.hasOwnProperty(id)) {
   ulHeights[id] = ul.height();
  }
 });    

 var animationDuration = 500;
 function toggleOnClick() {
  var ul = $(this).parent().children('ul');
  var img = $(this).parent().children('img');

  ul.children('li').children('div').children('ul')
    .each(function() {
   $(this).parent().children('img').attr('src','/plus.gif');
   $(this).animate({height: 0}, {duration: 0});
  });  

  if (ul.height() == 0) { 
    img.attr('src', 'minus.gif');       
    ul.animate({height: ulHeights[ul.attr('id')]}, 
      {
		  duration: animationDuration,
		  complete: function(){$(this).height('auto');}
		}
	);
  } else {
    img.attr('src', 'plus.gif');        
    ul.animate({height: 0}, {duration: animationDuration});
  }
 }
 toggleElements.click(toggleOnClick);

 // reset nested list settings
 $('ul > li:has(div > ul)').css('list-style-type', 'none');

 $('ul > li > div').animate({marginLeft: '-15px'});
 
 $('ul').height(0);     
                                
});
</script>

Open in new window

0
 

Author Closing Comment

by:wintersun
ID: 34198044
Sudaraka, thanks for your quick guidance.
0
 
LVL 18

Expert Comment

by:Sudaraka Wijesinghe
ID: 34198361
Glad to help. Thanks for the points.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Increase image taller on inner pages 2 52
type of website 13 53
center div inside another div 2 32
css messed up 8 29
Developer portfolios can be a bit of an enigma—how do you present yourself to employers without burying them in lines of code?  A modern portfolio is more than just work samples, it’s also a statement of how you work.
Although a lot of people devote their energy toward marketing for specific industries, there are some basic principles that can be applied to any sector imaginable. We’ll look at four steps to take and examine how those steps were put into action fo…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.
The viewer will learn the benefit of using external CSS files and the relationship between class and ID selectors. Create your external css file by saving it as style.css then set up your style tags: (CODE) Reference the nav tag and set your prop…

751 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question