Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

UL and Nested UL Height

Posted on 2010-11-22
8
Medium Priority
?
1,329 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
Survive A High-Traffic Event with Percona

Your application or website rely on your database to deliver information about products and services to your customers. You can’t afford to have your database lose performance, lose availability or become unresponsive – even for just a few minutes.

 

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 2000 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

Will your db performance match your db growth?

In Percona’s white paper “Performance at Scale: Keeping Your Database on Its Toes,” we take a high-level approach to what you need to think about when planning for database scalability.

Question has a verified solution.

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

Color can increase conversions, create feelings of warmth or even incite people to get behind a cause. If you want your website to really impact site visitors, then it is vital to consider the impact color has on them.
There’s a good reason for why it’s called a homepage – it closely resembles that of a physical house and the only real difference is that it’s online. Your website’s homepage is where people come to visit you. It’s the family room of your website wh…
The viewer will receive an overview of the basics of CSS showing inline styles. In the head tags set up your style tags: (CODE) Reference the nav tag and set your properties.: (CODE) Set the reference for the UL element and styles for it to ensu…
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)

722 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