Help with show / hide text please?

Hi

I have a lot of text in a few sections for one page. I want to use a show / hide to expand and close the extended detailed if the user wants to read more.

At the moment I have a solution, the open link appears in the middle of the text where I want it, but when the user clicks to extend the text, the link stays in the same place… I would like it to appear at the bottom of the extended text.

I am not sure how to change this. Do you have any ideas?

Any help would be much appreciated.

Here is my current code

<h1 id="headline">Headliner</h1>

<p>opening paragraphs....</p>
 
 <a href="" class="readmore">Read More..</a>

<div class="hiddenContent">

           <p>Extended content when the user clicks.</p>    
  
  </div>   <!-- /hiddenContent-->    
     
 <script>
      $('.hiddenContent').hide();
      $('.readmore').click(function () {
        $('.hiddenContent').slideToggle('slow', function(){
          $('.readmore').text($(this).is(':visible')? 'Close' : 'Read More..');
        })
        return false;
      });
    </script>
                 

Got sorted with this!


   <script>
		  $(document).ready(function() {
			$('.hidden_software').hide().before('<a href="#" id="open-hidden_software" class="link">Read More &darr;</a>');
			$('.hidden_software').append('<a href="#" id="close-hidden_software" class="link">Close &uarr;</a>');
			$('a#open-hidden_software').click(function() {
				$('.hidden_software').slideDown(1000);
				$('#open-hidden_software').fadeOut(500);
				return false;
			});
			$('a#close-hidden_software').click(function() {
				$('.hidden_software').slideUp(1000);
				$('#open-hidden_software').fadeIn(500)
				return false;
			});


I have a related problem trying to change/update text using slideToggle(). The code below gets me partway there, the page loads with the text, “Show Data Table”. The first click will display the table and change the text, but while subsequent clicks can close the table, the text never changes back.

Am I using .is(‘visible’) wrong?

I know that .is() works on booleans, Where can I learn more about it?

HTML:

<div id="TableContainer">
  <h1 id="Header">Show Data Table</h1>
    <TABLE id="Table" width="100%">
...
    </Table>
</div>

JS:

$(function(){
  $("#Header").click(function(){
    $("#Table").slideToggle(150);
    
    if ($('#Table').is(':visible')) {
      $("#Header").text('Hide Data Table');
    } else {
      $("#Header").text('Show Data Table');
    }
  });
});

Hi derekhed,
My analysis is:

Starting default:

  • Text-line is “Show Data Table”
  • #table has {display:none;} and {height: 1px;}

First click:

  • slideToggle is running forward
  • #table gets immediately {display:block;} and then growing height
  • so $(‘#Table’).is(‘:visible’), and text-line is “Hide Data Table”

Second click:

  • slideToggle is running backward
  • #table has still {display:block;} while shrinking height
  • Just at the click: still $(‘#Table’).is(‘:visible’), and text-line remains “Hide Data Table”
  • Only if slideToggle is ready, #table gets {display:none;}, but that’s too late to switch the text! :wink:

Conclusion: there has to be made a delay of 150ms (or a bit more for safety), before the if statement can go on.
In normal javascript you can do that with a setTimeout() function, I don’t know how that can be accomplished in jQuery, but I guess something like:

$(function(){
  $("#Header").click(function(){
    $("#Table").slideToggle(150);
    setTimeout(toggleText, 200);
  });
});

function toggleText(){
    if ($('#Table').is(':visible')) {
      $("#Header").text('Hide Data Table');
    } else {
      $("#Header").text('Show Data Table');
    }
}

Or to be independent from the visibility, just check the content of the text in the #Header; something like:

$(function(){
  $("#Header").click(function(){
    $("#Table").slideToggle(150);
    
    if ( $("#Header").text.is( "Show Data Table" ) ) {
      $("#Header").text('Hide Data Table');
    } else {
      $("#Header").text('Show Data Table');
    }
  });
});

Does that make sense for a jQuery-noob as I am? :slight_smile:

I’ve only gotten to page 35 in my jQuery book, so I’ve got you beat for jQuery-noobdom!

Thanks, the first example you posted worked like a charm. I’d prefer the second as it doesn’t rely on timing (?), but I couldn’t get it to work - the text would never change.

How common are timing issues where you’d need to use setTimeout()?

Hi derekhed,

Timing things can be different: if you have to wait until something has happened, sometimes you can embed it in the function itself (for instance: after a loop has taken place), and sometimes you’ll need the timeOut() function.

  • Yes I prefer the second too: indeed it doesn’t rely on timing.
    I tried to get it working (didn’t test it before), and no success either: lack of jQuery knowledge! :wink:

But I have mixed up the second with normal javascript, which I can oversee.
The principle is this:

<p id="showme">Show more please!</p>
<div id="lorem">
      <h2>More!</h2>
      <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem nonummy nibh 
      ...
</div>
<script type="text/javascript">
$(document).ready(function(){
	$("#showme").click(function(){
		$("#lorem").slideToggle(500);

		var showme=document.getElementById('showme');
		if (showme.innerHTML=="Show more please!"){
			showme.innerHTML="Hide more please!";
		}
		else {	
			showme.innerHTML="Show more please!";
		}
	});
});
</script>

For the accessibility I added some extras: if the visitor is browsing without javascript, the More-text may not be invisible forever! So without js the More-text has to be always visible, and the click-option has to be hidden:

#showme {
	....
	display: none;
	}
<script type="text/javascript">
$(document).ready(function(){
	var showme=document.getElementById('showme');
	showme.style.display="block";
	var lorem=document.getElementById('lorem');
	lorem.style.display="none";

	$("#showme").click(function(){
		$("#lorem").slideToggle(500);
		if (showme.innerHTML=="Show more please!"){
			showme.innerHTML="Hide more please!";
		}
		else {	
			showme.innerHTML="Show more please!";
		}
	});
});
</script>

And that is working. :slight_smile:

Thanks for that. This is similiar to the example in my book. However, it doesn’t work when I apply it to my situation, not sure why. I’m showing/hiding a table, and that might have something to do with it…

I like how the latest example is set up for non-JS situations, and I’ve added that to my code.

I think what I’d like to do is explore the use of a call-back to eliminate the setTimeout(). Wouldn’t that be the cleanest way to do this when using the setTimeout() is the ONLY way I’ve gotten this to work so far?

Adding your suggestions, the table’s initial display is ‘table’, and the header’s initial display is ‘none’ in the CSS file.


$(function(){
  // if javascript is not enabled, no toggle is possible: 
  // the Table is visible by default, and "Show ..." is hidden by default.
  
  // if JS is enabled, Header text has to be visible
  $('#Header').css('display', 'block');
  
  // if JS is enabled, 'Show..' text has to be invisible before toggling
  $('#Table').css('display', 'none');
  
  $("#Header").click(function(){
    $("#Table").slideToggle(150, function(){
      if ($('#Table').is(':visible')) {
        $("#Header").html('Hide Data Table &uarr;');
      } else {
        $("#Header").html('Show Data Table &darr;');
      }
    });
  });
});

Yes, it’s due to the table.

The table doesn’t slide out slowly: is visible at once.
But if you wrap the whole table in a <div id=“Tablewrapper”>, it’s working.

I’m a jquery beginner also but I believe you can accomplish this easily by using a callback in jquery which will wait for the animation to complete before running the check for visible.


 myHeader.click(function () {
        myTable.slideToggle("slow", function () {
            // Animation complete.
            if (myTable.is(':visible')) {
                myHeader.text('Hide Data Table');
            } else {
                myHeader.text('Show Data Table');
            }
        });
    });
});

Otherwise the jquery just gets on with the next rule while the animation is running and of course its still visible until the animation is complete.

Full example.
e.g.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js "></script>
<style type="text/css">
#Header{cursor:pointer}
</style>
</head>

<body>
<div id="TableContainer">
		<h1 id="Header">Hide Data Table</h1>
		<table id="Table" width="100%">
				<tr>
						<td>This is  a test</td>
				</tr>
				<tr>
						<td>This is  a test</td>
				</tr>
				<tr>
						<td>This is  a test</td>
				</tr>
				<tr>
						<td>This is  a test</td>
				</tr>
				<tr>
						<td>This is  a test</td>
				</tr>
				<tr>
						<td>This is  a test</td>
				</tr>
		</table>
</div>
<script type="text/javascript">
$(function () {
    var myHeader = $("#Header");
    var myTable = $("#Table");

    myHeader.click(function () {
        myTable.slideToggle("slow", function () {
            // Animation complete.
            if (myTable.is(':visible')) {
                myHeader.text('Hide Data Table');
            } else {
                myHeader.text('Show Data Table');
            }
        });
    });
});
</script>
</body>
</html>


Hey Paul,

You will also have to add:

#Table{display:inline-block;}

to your CSS for the slideToggle effect to work properly.

Also, you could write this:

if (myTable.is(':visible')) {
  myHeader.text('Hide Data Table');
} else {
  myHeader.text('Show Data Table');
}

as this:

myHeader.text( (myTable.is(':visible')? "Hide" : "Show") + " Data Table");

although when I read it, I think your version is better :slight_smile:

Ah ok :slight_smile: I see Francky mentioned that a table wrapper was needed also to make it slide nicely. I wonder why jquery doesn’t slide the table nicely by default?

Changing the table to display:inline-block makes it slide nicely but of course ruins the table layout for the data as its no longer a table.

I added a wrapper and it slides nicely now:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js "></script>
<style type="text/css">
#Header { cursor:pointer }
td { padding:10px }
</style>
</head>

<body>
<div id="TableContainer">
		<h1 id="Header">Hide Data Table</h1>
		<!-- add a wrapper for the slideToggle to take effect -->
		<div id="Table">
				<table width="100%">
						<tr>
								<td>This is  a test</td>
								<td>This is  a test</td>
								<td>Third cell</td>
						</tr>
						<tr>
								<td>This is  a test</td>
								<td>This is  a test</td>
								<td>Third cell</td>
						</tr>
						<tr>
								<td>This is  a test</td>
								<td>This a test</td>
								<td>Third cell</td>
						</tr>
						<tr>
								<td>This is  a test</td>
								<td>This test</td>
								<td>Third cell</td>
						</tr>
						<tr>
								<td>This is  a test</td>
								<td>This is  a test</td>
								<td>Third cell</td>
						</tr>
						<tr>
								<td>This is  a test</td>
								<td>This is  a test</td>
								<td>Third cell</td>
						</tr>
				</table>
		</div>
</div>
<script type="text/javascript">
$(function () {
    var myHeader = $("#Header");
    var myTable = $("#Table");

    myHeader.click(function () {
        myTable.slideToggle("slow", function () {
            // Animation complete.
            if (myTable.is(':visible')) {
                myHeader.text('Hide Data Table');
            } else {
                myHeader.text('Show Data Table');
            }
        });
    });
});
</script>
</body>
</html>

I also notice (from recent experience) that any margins on the element that is sliding causes the slide to be very jumpy so are best avoided.

Also, you could write this:

if (myTable.is(':visible')) {
  myHeader.text('Hide Data Table');
} else {
  myHeader.text('Show Data Table');
}

as this:

myHeader.text( (myTable.is(':visible')? "Hide" : "Show") + " Data Table");

I thought about doing that but I can never remember that syntax from memory :slight_smile: I need to spend more time practising what I’ve learnt as I soon forget.

Yes, that’s a better alternative for the #Tablewrapper I added to get it working. :slight_smile:

If this and Paul’s call back is implemented in my unobtrusive example, then:

  • Test: [U]jquery-slide-toggle-table-2.htm[/U]

    (the switches for the display=“block”/“none” have now to be written in jQuery language too)
    (the trigger line #Header is given a {float: left;} with a clear for the next line, so only the words are clickable and not the whole trigger line) :wink:

=======

In my test I didn’t see difficulties. :rolleyes:

(shorthand notation if/else) I thought about doing that but I can never remember that syntax from memory. :slight_smile:

You have at least 1 colleague. :smiley:

That’s a great demo, Francky!
Nice work.

Yes its not obvious with your example but if you remove the data from the cells you can soon see the difference.


<table id="Table">
		<tr>
				<td class="topcornerLeft">prisoner<br />
						in cell 1</td>
				<td class="topcornerRight"><h2>More!</h2></td>
				<td class="topcornerRight"><h2>More!</h2></td>
		</tr>
		<tr>
				<td>prisoner<br />
						in cell 2</td>
				<td class="topcornerRight"><h2>More!</h2></td>
				<td><p>Lorem ipsum .</p></td>
		</tr>
		<tr>
				<td>prisoner<br />
						in cell 3</td>
				<td> hello </td>
				<td class="topcornerRight"><h2>More!</h2></td>
		</tr>
		<tr>
				<td class="bottomcornerLeft">dining room</td>
				<td class="bottomcornerRight"> test </td>
				<td class="topcornerRight"><h2>More!</h2></td>
		</tr>
</table>


The cells no longer stretch to fit the table and sit huddled up at the side. Toggle the display and you will see the difference.:slight_smile:

The cells no longer have a table parent so an anonymous table parent is created by the browser at the width of the data cells only. That means you won’t get the equal distribution of cells across the width of a 100% table. It just behaves like a width-less table no matter how much you try to change it.

In your example the content in the cells themselves pushes the cells wide until they span al the way across but if you had content that didn’t reach the edge of the cell (as in most table data structures) you would see the table collapse.

Rather than wrapping a div around the table you could in your example add a tbody element inside the table and give that a display:table and 100% width.


tbody{display:table;width:100%}

However if you have a thead section then you can’t use that approach because that would give you two separate tables and no cell alignment between thead and tbody.

There is also an issue in adding display:inline-block to the table as it stops height being a minimum and if you apply a height of 200px to the table the table content overflows and spills out unlike a real table where the table always accommodates the content.

The outcome is that display:inline-block for the table element could work in some limited situations but as an overall solution is totally unreliable. The best advice is to wrap the table in a div instead.:slight_smile:

Yes, of course, it’s loud & clear; if you strip of the basic feature of a table, he’ll not behave as a table! :slight_smile:

Conclusion: it’s allowed to put the wrapper-div around the table without saddling the html with superfluous code.
Then my 3rd arrow, with the wrapper comeback, should be the definitive [U]180[/U] for one roll out table:

Now only a clever jQuery specialist who can convert this in classes, in order that [B]more /B show/hide tables on one page are possible. :wink:

Nice demo Francky :slight_smile:

I’m not clever at jquery but I think this will work :slight_smile:


<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>jquery slideToggle() Table (3)</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<!-- http://www.sitepoint.com/forums/showthread.php?1171990-Help-with-show-hide-text-please -->
<style type="text/css">
html {
	height: 100%;
	padding-bottom: 1px;
}
body {
	width: 850px;
	margin: 0 auto;
	padding-bottom: 20px;
	font-family: "Trebuchet MS", arial, helvetica, sans-serif;
}
.header {
	float: left;
	padding: .1em 10px;
	margin-bottom: 10px;
	color: blue;
	background: #F5F5FF;
	border: 1px solid green;
	border-radius: 10px;
	cursor: pointer;
	display: none;
}
.Tablewrapper { clear: both; }
.Table {
	width: 100%;
	border: 1px solid green;
	border-radius: 10px;
	box-shadow: 5px 5px 5px #C0C0C0;
}
.Table td {
	border: 1px solid #C0C0C0;
	padding: 0 10px;
}
.topcornerLeft { border-radius: 8px 0 0 0; }
.topcornerRight { border-radius: 0 8px 0 0; }
.bottomcornerLeft { border-radius: 0 0 0 8px; }
.bottomcornerRight { border-radius: 0 0 8px 0; }
.Table p { font-size: .9em; }
.clearBoth { clear: both; }
pre { color: #0000C0; }
pre span { color: #808080; }
</style>
</head>

<body>
<h1>jquery slideToggle() Table (3)</h1>
<p class="header">Show Data Table &#8595;</p>
<div class="Tablewrapper">
		<table class="Table">
				<tr>
						<td class="topcornerLeft">prisoner<br />
								in cell 1</td>
						<td class="topcornerRight"><h2>More!</h2></td>
				</tr>
				<tr>
						<td>prisoner<br />
								in cell 2</td>
						<td><p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem nonummy nibh 
										euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. Ut wisis enim 
										ad minim veniam, quis nostrud exerci tution ullamcorper suscipit lobortis nisl 
										ut aliquip ex ea commodo consequat.<br />
										Duis te feugifacilisi. Duis autem dolor in hendrerit in vulputate velit esse 
										molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros 
										et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit 
										au gue duis dolore te feugat nulla facilisi.</p></td>
				</tr>
				<tr>
						<td>prisoner<br />
								in cell 3</td>
						<td><pre><p id=&quot;header&quot;>Show Data Table &darr;</p>
<div id=&quot;Tablewrapper&quot;>
   <table id=&quot;Table&quot;>
      <tr>
         <td class=&quot;topcornerLeft&quot;>prisoner<br />in cell 1</td>
         <td class=&quot;topcornerRight&quot;><h2>More!</h2></td>
      </tr>
      ...
   </table>
</div>
<p class=&quot;clearBoth&quot;>This is the next line, lorem ...</p></pre></td>
				</tr>
				<tr>
						<td class="bottomcornerLeft">dining room</td>
						<td class="bottomcornerRight"><pre>$(function () {
   var myheader = $(&quot;.header&quot;);
   var myTablewrapper = $(&quot;.Tablewrapper&quot;);
   myheader.css(&quot;display&quot;, &quot;block&quot;);
   myTablewrapper.css(&quot;display&quot;, &quot;none&quot;);

   myheader.click(function(){
      myTablewrapper.slideToggle(500, function() {
         <span>// Animation complete.</span>
         if (Tablewrapper.is(&#39;:visible&#39;)) {
            myheader.text(&#39;Hide Data Table &#8593;&#39;);
         } else {
            myheader.text(&#39;Show Data Table &#8595;&#39;);
         }
      });
   });
});</pre></td>
				</tr>
		</table>
</div>
<p class="clearBoth">This is the next line, lorem ...</p>
<p class="header">Show Data Table &#8595;</p>
<div class="Tablewrapper">
		<table class="Table">
				<tr>
						<td class="topcornerLeft">prisoner<br />
								in cell 1</td>
						<td class="topcornerRight"><h2>More!</h2></td>
				</tr>
				<tr>
						<td>prisoner<br />
								in cell 2</td>
						<td><p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem nonummy nibh 
										euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. Ut wisis enim 
										ad minim veniam, quis nostrud exerci tution ullamcorper suscipit lobortis nisl 
										ut aliquip ex ea commodo consequat.<br />
										Duis te feugifacilisi. Duis autem dolor in hendrerit in vulputate velit esse 
										molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros 
										et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit 
										au gue duis dolore te feugat nulla facilisi.</p></td>
				</tr>
				<tr>
						<td>prisoner<br />
								in cell 3</td>
						<td><pre><p id=&quot;header&quot;>Show Data Table &darr;</p>
<div id=&quot;Tablewrapper&quot;>
   <table id=&quot;Table&quot;>
      <tr>
         <td class=&quot;topcornerLeft&quot;>prisoner<br />in cell 1</td>
         <td class=&quot;topcornerRight&quot;><h2>More!</h2></td>
      </tr>
      ...
   </table>
</div>
<p class=&quot;clearBoth&quot;>This is the next line, lorem ...</p></pre></td>
				</tr>
				<tr>
						<td class="bottomcornerLeft">dining room</td>
						<td class="bottomcornerRight"><pre>$(function () {
   var myheader = $(&quot;.header&quot;);
   var myTablewrapper = $(&quot;.Tablewrapper&quot;);
   myheader.css(&quot;display&quot;, &quot;block&quot;);
   myTablewrapper.css(&quot;display&quot;, &quot;none&quot;);

   myheader.click(function(){
      myTablewrapper.slideToggle(500, function() {
         <span>// Animation complete.</span>
         if (Tablewrapper.is(&#39;:visible&#39;)) {
            myheader.text(&#39;Hide Data Table &#8593;&#39;);
         } else {
            myheader.text(&#39;Show Data Table &#8595;&#39;);
         }
      });
   });
});</pre></td>
				</tr>
		</table>
</div>
<p class="clearBoth">This is the next line, lorem ...</p>
<script type="text/javascript">

$(function () {
	$(".header").show();
	$(".Tablewrapper").hide();
	$(".header").click(function(){
		 var myTablewrapper = $(this).next('.Tablewrapper');
			var header = $(this);
		myTablewrapper.slideToggle(500, function() {
            // Animation complete.
            if (myTablewrapper.is(':visible')) {
                header.text('Hide Data Table &#8593;');
            } else {
                header.text('Show Data Table &#8595;');
            }
        });
    });
});

</script>
</body>
</html>