Toggle data display inside table cell - javascript

I have a table that's generated by a normal PHP loop. What I want to do is create a form in the first column of each row that's hidden by default but appears when you click a toggle link in that row.
I can make a normal toggle-able div by creating a CSS id called hidden and setting display: none;. Unfortunately I can't keep creating divs with id=hidden that are automatically associated with the preceding link.
I am pretty inexperienced with both Javascript and CSS, so I've mostly tried to do this by patching together examples but I'm coming up empty. I've read in some places that you can't put divs inside of a table, so maybe I'm going about this all wrong.
Here's an example of what the code does and how I wish it worked, but of course it does not.
<script language="JavaScript" type="text/javascript">
function toggle(id) {
var state = document.getElementById(id).style.display;
if (state == 'block') {
document.getElementById(id).style.display = 'none';
} else {
document.getElementById(id).style.display = 'block';
}
}
</script>
<?php
while($array = mysql_fetch_array($sql))
{
?>
<tr>
<td>
<?php
echo $array['some_data'];
?>
Toggle
<div id="hidden"><?php echo $array['hidden_thing']; ?></div>
</td>
<td>
<?php echo $array['some_other_data']; ?>
</td>
</tr>
<?php
}
?>

Just use a different ID for each row:
<?php
$count = 0;
while($array = mysql_fetch_array($sql)) {
$id = 'hidden' . $count++;
$data = $array['some_data'];
$hidden = $array['hidden_thing'];
$other_data = $array['other_data'];
echo <<<END
<tr>
<td>$data <a href="#" onclick="toggle('$id');>Toggle</a>
<div id="$id">$hidden_thing</div>
</td>
<td>$other_data</td>
</tr>
END;
}

Make it a span instead of a DIV as I think that some browsers don't support divs inside table elements. Also, instead of referring to it by ID, pass in this.nextSibling() to the toggle, using DOM navigation to get the next sibling (which should be the SPAN) to show/hide.
function toggle(ctl) {
var state = ctl.style.display;
if (state == 'block') {
document.getElementById(id).style.display = 'none';
} else {
document.getElementById(id).style.display = 'block';
}
}
<a href="#" onclick="toggle(this.nextSibling);">Toggle
</a><div><?php echo $array['hidden_thing']; ?></div>
EDIT: As #tomhaigh suggests (and as shown in the example), for this to work you need to make sure that there is no text/whitespace between the anchor and the div. You could also write a function that, given a DOM element, would select the next non-text DOM element and return it. Then pass this to that function and the result to your toggle function.

Here's my recommended (general solution) using jQuery to reference events relatively instead of maintaining ids for each row and form. This also allows you to hide non-active row forms easily, which is a good idea since only one form can be submitted at a time.
HTML:
<table id="tableForms" class="table">
<tr>
<td class="rowForm"><form><span>form1 content</span></form></td>
<td class="showRowForm">click on row to show its form</td>
</tr>
<tr>
<td class="rowForm"><form><span>form2 content</span></form></td>
<td class="showRowForm">click on row to show its form</td>
</tr>
<tr>
<td class="rowForm"><form><span>form3 content</span></form></td>
<td class="showRowForm">click on row to show its form</td>
</tr>
</table>
Javascript:
<script type="text/javascript" src="/assets/js/jquery.min.js"></script>
<script type="text/javascript">
//as soon as the DOM is ready, run this function to manipulate it
$(function() {
// get all tr elements in the table 'tableForms' and bind a
// function to their click event
$('#tableForms').find('tr').bind('click',function(e){
// get all of this row's sibblings and hide their forms.
$(this).siblings().not(this).find('td.rowForm form').hide();
// now show the current row's form
$(this).find('td.rowForm form').show();
}).
// now that the click event is bound, hide all of the forms in this table
find('td.rowForm form').hide();
});
</script>
Demo:
A working demo of this can be found here.

Related

Need help aligning dynamic td element in html form

I have the following piece of code:
<tr>
<td style="display:none;" id="missing_person_report_label"><b>Enter image</b></td>
<td style="display:none;" id="missing_person_report_image"><input type="file"><br/></td>
</tr>
These td elements are initially set as hidden and are only displayed when I'm selecting the "Missing Person Report" option from the dropdown menu. The Javascript function to activate these td elements is given as:
function checkForChange(that) {
if (that.value == "missing_person_report") {
console.log(that.value);
console.log('person');
document.getElementById("missing_person_report_label").style.display = "block";
document.getElementById("missing_person_report_image").style.display = "block";
}
}
The code is doing as intended but there is a problem with the alignment of the tr element. This is the screenshot of the webpage.
I want the Choose file to have the same alignment as all the above elements,i.e. I want the Choose file to be on the right side of the Enter Image label . How do I do it?
Edit: Full Code is available here:
Edit: Those who are saying that I should assign the style to tr instead of td, I already tried doing this. If I do this, the webpage looks like this:
I want all the elements on the right to have the same alignment.
#Ronith.
Actially you their CSS as block, so that's why they are on separated lines. You should set display = "table-cell"
table {
width: 100%;
}
td {
display: table-cell;
}
<table>
<tr>
<td
id="missing_person_report_label"><b>Enter image</b></td>
<td
id="missing_person_report_image"><input type="file"></td>
</tr>
</table>
P.S.: do not pay attention that display is in CSS. It's just for instance. You should set it from JS code as you wish
display:block; makes a html element to take the full width of it's parent. So, you made tds to block level element they took all the width available and the upper one pushed the second one below.
Solution is not to change it's default display property. However try with inline-block or table-cell; which is the default property for tds inside a table.
The issue is because of display:block in javascript. set display: inline-block in your javascript code:
document.getElementById("missing_person_report_label").style.display = "inline-block";
document.getElementById("missing_person_report_image").style.display = "inline-block";
try this - apply display none to tr and not the td and from the function display block it again
<tr style="display:none;" id="missing_person_report_row">
<td><b>Enter image</b></td>
<td><input type="file"><br/></td>
</tr>
Function
function checkForChange(that) {
if (that.value == "missing_person_report") {
console.log(that.value);
console.log('person');
document.getElementById("missing_person_report_row").style.display = "block";
}
}

HTML show/hide parts of a table onclick of table headers

I have a nested HTML table. I would like to show parts of the nested table depending on the header clicked using javascript
http://jsfiddle.net/TtWTR/103/
so far it shows all three parts. I want to click header A and show only optionA, click headerB and only show optionB etc etc. Not sure if ive set it up right as all three are showing. thanks
To achieve expected result, use below option oh hide() and show() methods
$('.trigger').click(function() {
console.log($(this).text())
var selectedHdr = $(this).text();
$('.nested tr').hide();
$('.nested tr#'+selectedHdr).show();
});
https://codepen.io/nagasai/pen/vdabJQ
Usually I find it convenient to use CSS class selectors on the "root" element (in your case that would be .toptable) allowing you to toggle it to show and hide child elements.
<table class="toptable">
<tr class="accordion">
<td class="A trigger">A</td>
<td class="B trigger">B</td>
<td class="C trigger">C</td>
</tr>
<tr>
<td>
<table>
<tr class="content A">
<!-- will toggle using show-A -->
</tr>
</table
</td>
</tr>
</table>
Then you can make sure to hide the .content rows using CSS unless specific classes are set on the top table:
.content {
display: none; /* content hidden by default */
}
.show-A .A.content {
display: table; /* show when the parent table has .show-A set */
}
Now you just have to add event listeners to your triggers to toggle the classes for the different content rows:
const toptable = document.querySelector('.toptable');
['A', 'B', 'C'].forEach((group) => {
const trigger = document.querySelector(`.${group}.trigger`);
trigger.addEventListener('click', () => {
toptable.classList.toggle(`show-${group}`);
});
});
This can be done using the following script
$('.nested').hide();
$('tr .trigger').click(function() {
var target_id= "#"+$(this).attr('id')+"-table";
$('.nested').not(target_id).hide();
$(target_id).show();
});
and is shown in http://jsfiddle.net/TtWTR/152/

Using each() for checking which class is clicked

So here's my problem, I'm new to jQuery. What I am trying to do here is check for user to click on a certain table cell/row and it would then display a div named popup of an index the same as the table cell votes. Without having to make separate functions of all the rows in my table.
Using some numerical value will display all the dialogs from a click of the cell of the same value the first time and from the second time only the correct one.
I bet there's some other way to do it and maybe there's just a stupid error.
Using the index value in the click and dialog function won't work.
I am open to suggestions on improvement also.
The scripts:
<script type='text/javascript'>
$(document).ready( function() {
$('.votes').each(function(index) {
$('.votes:eq(index)').click(function() {
$('.popup:eq(index)').dialog();
});
});
});
</script>
HTML for the table part, only a snippet
<td class='votes'>5</td>
<td class='votes'>15</td>
<td class='votes'>25</td>
HTML for the div part, only a snippet of the div:
<div class='popup'>
<ul>
<li>John Johnsson</li>
<li>John Doe</li>
</ul>
</div>
<div class='popup'>
<ul>
<li>Matt Theman</li>
<li>Peter Watley</li>
</ul>
</div>
jsFiddle Demo
You don't have to iterate using each for .click, that will happen internally. You can use .index() to get the index of the element clicked with reference to its parent.
$('.votes').click(function() {
$('.popup').eq($(this).index()).dialog();
});
Initially, the main problem is that you are not using string concatenation to apply the index to the selector (demo):
$('.votes:eq(index)')
// the Sizzle selector engine doesn't know what the string "index" is.
instead of
$('.votes:eq(' + index + ')')
// using concatenation calls the .toString() method of index to apply "0" (or "1", "2", etc.)
// so that the parsed string becomes '.votes:eq(0)' which the Sizzle selector engine understands
Once the Sizzle selector engine understands which elements to target (demo), the second problem is how jQueryUI changes the DOM with the .dialog method.
Inital markup:
<table>
<tbody>
<tr>
<td class="votes">5</td>
<td class="votes">15</td>
<td class="votes">25</td>
</tr>
</tbody>
</table>
<div class="popup">
<ul>
<li>John Johnsson</li>
<li>John Doe</li>
</ul>
</div>
<div class="popup">
<ul>
<li>Matt Theman</li>
<li>Peter Watley</li>
</ul>
</div>
Once the first click event is handled, one of the div.popup elements is transformed into a jQueryUI Dialog and is appended to the body, removing it from its initial position, like so:
<table>
<tbody>
<tr>
<td class="votes">5</td>
<td class="votes">15</td>
<td class="votes">25</td>
</tr>
</tbody>
</table>
<div class="popup">
<ul>
<li>Matt Theman</li>
<li>Peter Watley</li>
</ul>
</div>
<div class="ui-dialog ui-widget ..."> ... </div>
So your initial indexes no longer apply. Fortunately, there are several solutions to both problems (a few of which I've listed below).
Solutions to Problem 1:
Use string concatenation as described above.
Use the .eq method instead, which will accept the index variable as-is
Use a delegate handler instead and grab the index from within the handler:
Example of 2:
$('.votes').eq(index);
Example of 3:
$('table').on('click', '.votes', function (e) {
var vote = $(this),
index = vote.parent().index(vote);
});
Solutions to Problem 2:
Create all of the dialogs initially and open them as needed.
Create the dialogs using a deep clone of the div element. (Not recommended)
Remove the td element to match the removed and re-appended div element. (Not recommended)
Example of 1:
var popups = [];
$('.popup').each(function (i, elem) {
var popup = $(elem).data('index', i).dialog({
"autoOpen": false
});
popups.push(popup)
});
$('table').on('click', '.votes', function (e) {
var vote = $(this),
index = vote.index();
popups[index].dialog('open');
});
I'm sure there are other solutions as well, but these are the ones I thought of of the top of my head.
Functional demo: http://jsfiddle.net/2ChvX/2/
UPDATE:
With your chosen table structure, you're actually looking for the index of the parent tr element as that is what corresponds with the div.popup element. To get the index of the parent tr element, change the line that gets the index from:
index = vote.index();
to:
index = vote.parent().index();
Updated fiddle: http://jsfiddle.net/AZpUQ/1/
Updated
FWIW, here's an example using the jQueryUI dialog (which I presume you are using?) and javascript sectionRowIndex and cellIndex.
Reusable code allowing you to identify the cell the user clicked in and perform appropriate action.
http://jsfiddle.net/KbgcL/1/
HTML:
<table id="myTable">
<tr>
<th>Label:</th>
<th>Washington</th>
<th>Idaho</th>
<th>California</th>
</tr>
<tr>
<td class='label'>Votes</td>
<td class='votes'>5</td>
<td class='votes'>15</td>
<td class='votes'>25</td>
</tr>
<tr>
<td class='label'>Voters</td>
<td class='voters'>5,000</td>
<td class='voters'>15,000</td>
<td class='voters'>25,000</td>
</tr>
</table>
<div id="msg"></div>
jQuery/javascript:
var myTr;
$('#msg').dialog({
autoOpen:false,
title: 'Report:'
});
$('#myTable tr td').click(function() {
myTr = $(this).closest('td').parent()[0].sectionRowIndex;
myCell = this.cellIndex;
myState = $('#myTable').find('tr:eq(0)').find('th:eq(' +myCell+ ')').html();
myVoters = $('#myTable').find('tr:eq(' +myTr+ ')').find('td:eq(' +myCell+ ')').html();
if (myTr==2 && myCell==3){
//California
$('#msg').html('There are ' +myVoters+ ' voters in ' +myState);
$('#msg').dialog('open');
}else if(myTr==1 && myCell==1){
$('#msg').html('There were ' +myVoters+ ' votes made in ' +myState);
$('#msg').dialog('open');
}
});

Dynamic HTML IDs (PHP, Java, and a bit of SQL)

I'm trying to create a web page which generates a series of unique DIV IDs, each displaying different content based off of the entries in an SQL table.
Each div has a "hide" and "show" button, which work independently when manually giving each div a unique name.
I can get the divs themselves to generate based on class names in PHP, which displays the divs correctly.
The problem lies in the "hide" and "show" buttons since they're controlled by JavaScript. The code is as follows:
for ($j = 0 ; $j < $rows ; ++$j)
{
for($i =0; $i < $rows2; $i++)
{
if (mysql_num_rows($ans) > 0) //check if widget table is empty
{
$widgetusr[$j] = mysql_result($ans,$j,'wname')or die(mysql_error()); //user's widget
$widgetstore[$i] = mysql_result($ans2,$i,'wname'); //store widget
if($widgetusr[$j] == $widgetstore[$i] && $widgetusr[$j] != 'Medieval Calendar') //check if user has already purchased the widget
{
echo "<div class=widget_container".$j%2 .">"; //container divs are named 1 and 0. j mod 2 should return either 1 or 0
?>
<!----Start of weather Widget--->
<!---Script for show/hide buttons weather widget--->
<script>
var widg = "<?php echo $widgetusr[$j]; ?>";
var id = "#" + widg;
$(document).ready(function(){
$("#hide1").click(function(){
$(id).hide();
});
$("#show1").click(function(){
$(id).show();
});
});
</script>
<button id="hide1">Hide</button>
<button id="show1">Show</button>
<!---End Script for show/hide buttons weather widget--->
<?php
echo "<div class = 'widget' id='$widgetusr[$j]'>
</div>
</div>
<!----End of Widget---> ";
}
}
else
{
echo "You have no widgets please visit <a href='store.php'> the store </a> to purchase some. <br/>"; //widget table is empty. Redirect to widget store.
}
}
}
?>
I tried to pass the php varriable (containing an SQL value) to JavaScript (which works successfully, I was able to print out "#financial widget" as an id name.), however neither the show, nor hide button works. The generated divs all have the correct names also.
If additional information is required please ask. I tried to be as general as possible.
You really only need one button. Change your php to render the following html
<div class="widget_container">
<button class="btn ">Hide</button>
<div class="widget">widget1</div>
</div>
<div class="widget_container">
<button class="btn">Hide</button>
<div class="widget">widget2</div>
</div>
<div class="widget_container">
<button class="btn">Hide</button>
<div class="widget">widget3</div>
</div>
and output the following Outside of the loop, ensuring jQuery is loaded:
<script type="text/javascript">
//Standar jquery doc ready event, fires when the dom is loaded
$(document).ready(function(){
//add an event listener elements with a class of "btn"
$('.btn').click(function () {
//"this" is the element click, so we find siblings of this with a class
//of "widget" and toggle its visibility
$(this).siblings('.widget').toggle();
//Change the text of the button the below is short hand for:
//if($(this).text() == "Hide"){
// $(this).text("Show");
//}else{
// $(this).text("Hide");
//}
$(this).text($(this).text() == "Hide" ? "Show" : "Hide");
});
});
</script>
Example
Some useful links:
http://learn.jquery.com/using-jquery-core/document-ready/
http://api.jquery.com/click/
http://api.jquery.com/siblings/
http://api.jquery.com/closest/
http://api.jquery.com/toggle/
http://api.jquery.com/text/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
Example with fixed height widgets: http://jsfiddle.net/bdpm4/2/
Update 2
Perhaps a better way to do it: http://jsfiddle.net/bdpm4/3/
you should use class instead of id and dont put your $(document).ready() in the loop.
HTML:
<div class="widget_container">
<button class="btn hideBtn">Hide</button>
<button class="btn showBtn">Show</button>
<div class="widget">widget1</div>
</div>
<div class="widget_container">
<button class="btn hideBtn">Hide</button>
<button class="btn showBtn">Show</button>
<div class="widget">widget2</div>
</div>
JS:
$(document).ready(function(){
$('.btn').on('click', function (evt) {
var btn = $(evt.target);
btn.siblings('.widget').toggle();
btn.parent().find('.btn').toggle();
});
});
CSS:
.showBtn {
display:none;
}
here is an example: http://jsfiddle.net/xdA4r/4/

Displaying table as pop up/ on the top of HTML

I have a link in my datalist
details
<table style="display: none; background-color:AntiqueWhite; border-color:Black;
direction:rtl;" class="MyTable">
<tr>
<td>
<asp:Label ID="lblShowHide" runat="server"
Text='<%#DataBinder.Eval(Container.DataItem,"Description")%>'></asp:Label>
</td>
</tr>
</table>
On click of the link I am displaying the assciated table related to the link by the below function:
<script type="text/javascript" language="javascript">
function showHideDesc(link)
{
var table = link.parentNode.getElementsByTagName("TABLE")[0];
if (table.style.display == "none")
{
table.style.display = "";
link.innerHTML = "details";
}
else
{
table.style.display = "none";
link.innerHTML = "details";
}
}
</script>
Till now it is working fine, but the issue arises that the description which I am showing is of 10-15 lines and the table is hiding because of the other records in the datalist. I need to show this on the top of every HTML.. some Pop up kind of stuff.
Please help
To display your table above other HTML content, you should use the z-index CSS attribute. This enables some kind of layering of your content.
Take a look at http://w3schools.com/css/css_positioning.asp for some more info

Categories

Resources