[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1337
  • Last Modified:

UL and Nested UL Height

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
wintersun
Asked:
wintersun
  • 4
  • 4
1 Solution
 
Sudaraka WijesingheWeb Application ProgrammerCommented:
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
 
wintersunAuthor Commented:
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
 
Sudaraka WijesingheWeb Application ProgrammerCommented:
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
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
wintersunAuthor Commented:
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
 
wintersunAuthor Commented:

<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
 
Sudaraka WijesingheWeb Application ProgrammerCommented:
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
 
wintersunAuthor Commented:
Sudaraka, thanks for your quick guidance.
0
 
Sudaraka WijesingheWeb Application ProgrammerCommented:
Glad to help. Thanks for the points.
0

Featured Post

[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

  • 4
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now