SitePoint Sponsor |
|
User Tag List
Results 1 to 15 of 15
-
Mar 10, 2009, 16:04 #1
- Join Date
- Feb 2006
- Posts
- 257
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Change text depending on condition
Hi,
I have the following code that I use to loop though records in my database and display the text. For each record I look through the text for a certain piece of text and then split the content it is found. So for example if the database contained a field with the data "this is some text [splithere] this is some more text" then the first part (this is some text) would be displayed and then a more button would be shown. If the user clicked the more button then the rest of the content (this is some more text) would also be shown.
At the moment the more button is always shown, even if the [splithere] text was not found. What I'd like to do is only show the more button where necessary. I'd also like to change the text from 'more' to 'hide' when the button has been clicked and the additional content is being shown as when they click the link again the text is in fact hidden and so saying 'more' doesnt make any sense.
Here is the code I use:
Code:<?php $thetask = '1'; $number = '1'; $sql = "SELECT * FROM cases WHERE task_id = '$thetask' AND company_id = '1'"; $sqlresult = mysql_query($sql); while($row = mysql_fetch_array($sqlresult)) { $data = $row["body"]; ?><table width="600" border="0" cellpadding="5" cellspacing="0" bgcolor="#FFFFFF"> <tr> <td><?php $parts=explode('[splithere]',$data); foreach($parts as $i=>$part){ if($i==0){ echo '<p>'.$part.'</p>'; ?><span class="style2"> <?php }else{ echo '<p class="hidden" name="p'.$number.'">'.$part.'</p>'; } } echo '<script type="text/javascript"> function more(display, id){ var e=document.getElementsByTagName("p"); for(i=0; i<e.length; i++){ if(e[i].className=="hidden"&&(e[i].getAttribute("name")==id || id=="")) e[i].style.display = display==e[i].style.display?"none":display; } } more("none",""); </script>';echo '<p><a href="javascript:void(0)" onclick="more(\'block\',\'p'.$number.'\')">More</a></p>'; $number++; ?></span> </td> </tr> </table> <?php } ?>
Thanks a lot
-
Mar 10, 2009, 18:27 #2
- Join Date
- Jan 2007
- Location
- Christchurch, New Zealand
- Posts
- 14,729
- Mentioned
- 104 Post(s)
- Tagged
- 4 Thread(s)
From the look of your code I see that you plan to only have one split throughout the text. This is useful because the more/hide stuff can be performed without needing separate individual identifiers on each of the elements.
I'll start by using an html representation of how the existing php code shows three different lines, one with more text, another one without, and the last with more as well.
Code html4strict:<table width="600" border="0" cellpadding="5" cellspacing="0" bgcolor="#FFFFFF"> <tr> <td> <p>This is the first </p> <span class="style2"> <p class="hidden" name="p1"> that will be shown.</p> <script type="text/javascript"> function more(display, id){ var e=document.getElementsByTagName("p"); for(i=0; i<e.length; i++){ if(e[i].className=="hidden"&&(e[i].getAttribute("name")==id || id=="")) e[i].style.display = display==e[i].style.display?"none":display; } } more("none",""); </script> <p><a href="javascript:void(0)" onclick="more('block','p1')">More</a></p> </span> </td> </tr> </table> <table width="600" border="0" cellpadding="5" cellspacing="0" bgcolor="#FFFFFF"> <tr> <td> <p>This is the second.</p> <span class="style2"> <script type="text/javascript"> function more(display, id){ var e=document.getElementsByTagName("p"); for(i=0; i<e.length; i++){ if(e[i].className=="hidden"&&(e[i].getAttribute("name")==id || id=="")) e[i].style.display = display==e[i].style.display?"none":display; } } more("none",""); </script> <p><a href="javascript:void(0)" onclick="more('block','p2')">More</a></p> </span> </td> </tr> </table> <table width="600" border="0" cellpadding="5" cellspacing="0" bgcolor="#FFFFFF"> <tr> <td> <p>This is the third </p> <span class="style2"> <p class="hidden" name="p3"> that will be shown.</p> <script type="text/javascript"> function more(display, id){ var e=document.getElementsByTagName("p"); for(i=0; i<e.length; i++){ if(e[i].className=="hidden"&&(e[i].getAttribute("name")==id || id=="")) e[i].style.display = display==e[i].style.display?"none":display; } } more("none",""); </script> <p><a href="javascript:void(0)" onclick="more('block','p3')">More</a></p> </span> </td> </tr> </table>
Needless though it is to say, some improvements need to be made:
- I'll completely ignore the tables for layout issue, as that can be covered on another day
- The span doesn't work as intended because it's not allowed to wrap block-level elements such as paragraphs
- The same identical function definitely does not need to have multiple identical versions of itself being present
- The id attributes won't be needed for the hidden elements, because other forms of referencing can be performed instead
- Hiding the content by default causes the text to be unavailable to people without javascript
So what is wanted instead. I won't remove the tables, but I will use only one table inside of which will be the paragraphs. If you want a separate table around each individual paragraph then that is an easy change for you to make.
What I intend to have is one paragraph per result, with the more text inside that same paragraph, but surrounded by a classed span so that the script will know to look for and process that text.
Code html4strict:<p> This is the first <span class="more"> that will be shown.</span></p>
The class name allows our script to look through the page for all spans that have the "more" class
Code javascript:var spans = document.getElementsByTagName('span'), spansLen = spans.length, i; for (i = 0; i < spansLen; i += 1) { if (spans[i].className === 'more') { addMore(spans[i]); } }
There are fancier ways to get elements by their class name, but for now such techniques aren't required.
When each span with the "more" class name has been found, we add a more link to the page, with its own class name so that we can refer to it from css as well.
Code javascript:function addMore(el) { var a = document.createElement('a'); a.href = '#'; a.className = 'showMore'; if (el.nextSibling) { el.parentNode.insertBefore(a, el.nextSibling); } else { el.parentNode.appendChild(a); } hideMore.call(a); }
Placing the more link inline with the text makes it a lot easier to show and hide the text. It's place after the text though so that if you want the more link to be shown on a separate line, you can use some simple css to change it to a block-level element instead.
Code css:a.showMore { display: block; }
And finally, the showMore and hideMore functions update the more link, and show or hide the text that's in the span just before the more link itself.
Code javascript:function showMore() { this.innerHTML = 'Hide'; this.onclick = hideMore; this.previousSibling.style.display = ''; return false; } function hideMore() { var text = document.createTextNode('More'); this.innerHTML = 'More'; this.onclick = showMore; this.previousSibling.style.display = 'none'; return false; }
This now makes the php code a lot easier to write. Working backwards from our working showHide example, and using a couple of techniques to help manage the complexity, the php code would end up looking something like this:
Code php:$thetask = '1'; $sql = "SELECT * FROM cases WHERE task_id = '$thetask' AND company_id = '1'"; $sqlresult = mysql_query($sql); $tasks = ''; while($row = mysql_fetch_array($sqlresult)) { $data = $row["body"]; $parts=explode('[splithere]', $data); $tasks .= '<p>'; foreach ($parts as $i => $part) { if ($i == 0) { $tasks .= $part; } else { $tasks .= '<span class="more">' . $part . '</span>'; } } $tasks .= '</p>'; } if ($tasks != '') { echo <<< EOT <table width="600" border="0" cellpadding="5" cellspacing="0" bgcolor="#FFFFFF"> <tr> <td>$tasks</td> </tr> </table> <script type="text/javascript" src="showmore.js"> </script> EOT; }
When you have the final html representation of what you need first, it can be easier to create the php code afterwards because then you know what you need to achieve.
Here's the complete test html page for the showMore code.
Code html4strict:<html> <head> <style type="text/css"> .showMore { display: block; } </style> </head> <body> <table width="600" border="0" cellpadding="5" cellspacing="0" bgcolor="#FFFFFF"> <tr> <td> <p>This is the first <span class="more"> that will be shown.</span></p> <p>This is the second.</p> <p>This is the third <span class="more"> that will be shown.</span></p> </td> </tr> </table> <script type="text/javascript"> var spans = document.getElementsByTagName('span'), spansLen = spans.length, i; for (i = 0; i < spansLen; i += 1) { if (spans[i].className === 'more') { addMore(spans[i]); } } function addMore(el) { var a = document.createElement('a'); a.href = '#'; a.className = 'showMore'; if (el.nextSibling) { el.parentNode.insertBefore(a, el.nextSibling); } else { el.parentNode.appendChild(a); } hideMore.call(a); } function showMore() { this.innerHTML = 'Hide'; this.onclick = hideMore; this.previousSibling.style.display = ''; return false; } function hideMore() { var text = document.createTextNode('More'); this.innerHTML = 'More'; this.onclick = showMore; this.previousSibling.style.display = 'none'; return false; } </script> </body> </html>
Edit:
Closing script tag added to the php code, and adding return false to the end of showMore and hideMore functions.Last edited by paul_wilkins; Mar 11, 2009 at 16:47.
Programming Group Advisor
Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
Car is to Carpet as Java is to JavaScript
-
Mar 11, 2009, 02:04 #3
- Join Date
- Jan 2007
- Location
- Christchurch, New Zealand
- Posts
- 14,729
- Mentioned
- 104 Post(s)
- Tagged
- 4 Thread(s)
Does anybody have any criticism or commentary about the above?
I would also like to hear thoughts about the idea of using pre-created webpage solution to guide changes to the server-side code.Programming Group Advisor
Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
Car is to Carpet as Java is to JavaScript
-
Mar 11, 2009, 03:37 #4
- Join Date
- Feb 2006
- Posts
- 257
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Thanks very much for your incredibly detailed reply, I know I'm doing lots of things wrong but I don't have the time to re-do the whole thing from scratch!
I'm having a few problems getting the code to all work together though aqnd tbh I really don't understand JS at all so am having problems seeing how to resolve it.
Do you have a couple of minutes to throw together the code all together, integrating the PHP and the HTML so that I can see how it should all slot together? If not that's fine, I really appreciate the time you put in.
Thanks
-
Mar 11, 2009, 03:42 #5
- Join Date
- Jan 2007
- Location
- Christchurch, New Zealand
- Posts
- 14,729
- Mentioned
- 104 Post(s)
- Tagged
- 4 Thread(s)
The last two pieces of code above are the php and the html.
The php hasn't been tested because I don't have the resources available to hand, but it's pretty close to what's required.
The html in the last piece of code is a complete working html page that demonstrates a working page using the previously described techniques.Programming Group Advisor
Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
Car is to Carpet as Java is to JavaScript
-
Mar 11, 2009, 03:48 #6
- Join Date
- Feb 2006
- Posts
- 257
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Hi,
thanks a lot for the quick reply. The issue I'm having is knowing how to insert the data from the database in place of the <p>This is the first <span class="more"> that will be shown.</span></p> code in the HTML code that you displayed. I can get the PHP to work and output the full piece of data (without the [splithere] code), and I can use the HTML to display your sample data, I just don't know how to merge the two together.
Cheers
-
Mar 11, 2009, 04:00 #7
- Join Date
- Jan 2007
- Location
- Christchurch, New Zealand
- Posts
- 14,729
- Mentioned
- 104 Post(s)
- Tagged
- 4 Thread(s)
This code that I provided in the php part above does that.
Code php:while($row = mysql_fetch_array($sqlresult)) { $data = $row["body"]; $parts=explode('[splithere]', $data); $tasks .= '<p>'; foreach ($parts as $i => $part) { if ($i == 0) { $tasks .= $part; } else { $tasks .= '<span class="more">' . $part . '</span>'; } } $tasks .= '</p>'; }
After that the php code checks if $tasks contains anything, and if it does it then uses heredoc notation (that's the <<< EOT stuff) to display some html code with $tasks embedded inside that html.
Heredoc is a more powerful php technique than doublequote strings.Programming Group Advisor
Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
Car is to Carpet as Java is to JavaScript
-
Mar 11, 2009, 05:05 #8
- Join Date
- Feb 2006
- Posts
- 257
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Hi,
The code I used is:
Code:<?php $dbhostname = "blah"; $dbdatabase = "blah"; $dbusername = "blah"; $dbpassword = "blah"; $fgconnection = mysql_pconnect($dbhostname, $dbusername, $dbpassword) or die(mysql_error()); @mysql_select_db($dbdatabase) or die("Database error (error 1)"); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Untitled Document</title> <style type="text/css"> .showMore { display: block; } </style> </head> <body> <?php $thetask = '1'; $sql = "SELECT * FROM updates WHERE parent_id = '$thetask' AND company_id = '1'"; $sqlresult = mysql_query($sql); $tasks = ''; while($row = mysql_fetch_array($sqlresult)) { $data = $row["body"]; $parts=explode('[splithere]', $data); $tasks .= '<p>'; foreach ($parts as $i => $part) { if ($i == 0) { $tasks .= $part; } else { $tasks .= '<span class="more">' . $part . '</span>'; } } $tasks .= '</p>'; } if ($tasks != '') { echo <<< EOT <table width="600" border="0" cellpadding="5" cellspacing="0" bgcolor="#FFFFFF"> <tr> <td>$tasks</td> </tr> </table> <script type="text/javascript" src="showmore.js"> EOT; } ?> <script type="text/javascript"> var spans = document.getElementsByTagName('span'), spansLen = spans.length, i; for (i = 0; i < spansLen; i += 1) { if (spans[i].className === 'more') { addMore(spans[i]); } } function addMore(el) { var a = document.createElement('a'); a.href = '#'; a.className = 'showMore'; if (el.nextSibling) { el.parentNode.insertBefore(a, el.nextSibling); } else { el.parentNode.appendChild(a); } hideMore.call(a); } function showMore() { this.innerHTML = 'Hide'; this.onclick = hideMore; this.previousSibling.style.display = ''; } function hideMore() { var text = document.createTextNode('More'); this.innerHTML = 'More'; this.onclick = showMore; this.previousSibling.style.display = 'none'; } </script> </body> </html>
Any idea what I'm doing wrong?
CheersLast edited by grandad; Mar 11, 2009 at 05:56.
-
Mar 11, 2009, 05:32 #9
- Join Date
- Jan 2007
- Location
- Christchurch, New Zealand
- Posts
- 14,729
- Mentioned
- 104 Post(s)
- Tagged
- 4 Thread(s)
Look at the web page source code
Code htmlstrict:... </table> <script type="text/javascript" src="showmore.js"> <script type="text/javascript"> var spans = document.getElementsByTagName('span'), ...
You need to make a choice. Either have the script code inline in the page, or load it in from an external source. I suggest the latter choice.
Save the javascript code out to an external file called showmore.js (or some other name of your liking) and use that external file instead of inline script code.
By the way, I just noticed something that needs to be fixed in that php code. The script reference needs to have a closing script tag.
Code html4strict:<script type="text/javascript" src="showmore.js"> </script>
Programming Group Advisor
Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
Car is to Carpet as Java is to JavaScript
-
Mar 11, 2009, 05:56 #10
- Join Date
- Feb 2006
- Posts
- 257
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I'm an idiot! It's working nicely now, thanks so much for your help.
-
Mar 11, 2009, 06:03 #11
- Join Date
- Jan 2007
- Location
- Christchurch, New Zealand
- Posts
- 14,729
- Mentioned
- 104 Post(s)
- Tagged
- 4 Thread(s)
You're welcome. Hey by the way - did you noticed that in moving the css and javascript out away from the html code, that it's easier to read and understand the source code?
And, what do you think about building the content in php first before wrapping it in other code. Is it easier to read and understand than the original technique where you try to echo the page sequentially line by line?Programming Group Advisor
Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
Car is to Carpet as Java is to JavaScript
-
Mar 11, 2009, 16:40 #12
- Join Date
- Feb 2006
- Posts
- 257
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Yes it did seem better to split it into separate files, but is there any advantage to doing this apart from it being easier to read?
Also, I noticed that when clicking the link to show/hide text it jumps back to the top of the page, so if I click a link after scrolling down it jumps to the top. Is there any way of avoiding this?
-
Mar 11, 2009, 16:45 #13
- Join Date
- Jan 2007
- Location
- Christchurch, New Zealand
- Posts
- 14,729
- Mentioned
- 104 Post(s)
- Tagged
- 4 Thread(s)
Yes there is. It can be achieved by returning false from the end of the event functions, showMore and hideMore. This prevents the default behaviour, of following the fake link, from occurring.
I'll update the original code as well for when others want to use it too.
Code javascript:function showMore() { this.innerHTML = 'Hide'; this.onclick = hideMore; this.previousSibling.style.display = ''; return false; } function hideMore() { var text = document.createTextNode('More'); this.innerHTML = 'More'; this.onclick = showMore; this.previousSibling.style.display = 'none'; return false; }
Programming Group Advisor
Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
Car is to Carpet as Java is to JavaScript
-
Mar 19, 2009, 05:36 #14
- Join Date
- Feb 2006
- Posts
- 257
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Sorry to re-open an old case, however I'm come up against another issue.
I'm using the following code:
Code:<?php $sql = "SELECT * FROM updates WHERE parent_id = '1' AND company_id = '4'"; $sqlresult = mysql_query($sql); $tasks = ''; while($row = mysql_fetch_array($sqlresult)) { $data = $row["body"]; $parts=explode('[reply above this]', $data); $tasks .= '<p>'; foreach ($parts as $i => $part) { if ($i == 0) { $tasks .= $part; } else { $tasks .= '<span class="more">' . $part . '</span>'; } } $tasks .= '</p>'; } if ($tasks != '') { echo <<< EOT <table width="600" border="0" cellpadding="5" cellspacing="0" bgcolor="#FFFFFF"> <tr> <td>$tasks</td> </tr> </table> <script type="text/javascript" src="showmore.js"></script> EOT; } ?>
Is there anything that can be done about this?
Cheers
-
Mar 19, 2009, 11:14 #15
- Join Date
- Jan 2007
- Location
- Christchurch, New Zealand
- Posts
- 14,729
- Mentioned
- 104 Post(s)
- Tagged
- 4 Thread(s)
What sort of html tags? An example of he html code that would go in the row would enable us to help you a lot better.
Programming Group Advisor
Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
Car is to Carpet as Java is to JavaScript
Bookmarks