tr:hover won't trigger on invisible td - javascript

I want to make a table in which hovering over a row makes some buttons appear for that row. Right now, I have the buttons (actually just text) always there, and when a table row is hovered over, I change the visibility on the buttons from hidden to visible. However, the hover event does not seem to trigger on a hidden td element, even though the event is actually on the tr. How can I fix this? I don't want to just set the opacity to 0 because then they still can be clicked on (right?). Eventually I want to be able to turn on and off the hover effect by adding/removing a class, so that is why the opacity doesn't work.
My code looks like this: http://jsfiddle.net/h7oh9xvk/
HTML:
<table>
<tr><td class='precell'>X</td><td>blablabla</td><td class='postcell'>[edit]</td></tr>
<tr><td class='precell'>X</td><td>blablabla</td><td class='postcell'>[edit]</td></tr>
<tr><td class='precell'>X</td><td>blablabla</td><td class='postcell'>[edit]</td></tr>
</table>
CSS:
.precell, .postcell {
visibility: hidden;
}
tr:hover .precell {
visibility:visible;
}
tr:hover .postcell {
visibility:visible;
}
Edit: Additional Information: One of the main problems seems to be that the space between td elements in a row does not seem to count as part of the row (does not trigger the hover event on the row). When I move the mouse horizontally from one cell to another, it seems there is a space between td's where the hover "shuts off." Is there a way to stop this? That might fix the problem.

You can use display: none / display: table-cell:
table {
table-layout: fixed;
}
.precell, .postcell {
display: none;
width:0px;
}
tr:hover .precell {
display: table-cell;
}
td {
display: inline-block;
float:left;
}
tr:hover .postcell {
display: table-cell;
}
tr, td {padding:0px;}
<table>
<tr>
<td class='precell'>X</td>
<td style="margin-left:15px;">blablabla</td>
<td class='postcell'>[edit]</td>
</tr>
<tr>
<td class='precell'>X</td>
<td style="margin-left:15px;">blablabla</td>
<td class='postcell'>[edit]</td>
</tr>
<tr>
<td class='precell'>X</td>
<td style="margin-left:15px;">blablabla</td>
<td class='postcell'>[edit]</td>
</tr>
</table>
Updated after #Mary Melody comment.

It seems that it is simply impossible to trigger a hover event in the way I wanted, but it turns out there is an easy solution. If we include a div within the td, and act on that instead, it works perfectly:
.precell, .postcell {
visibility: hidden;
}
tr:hover .precell {
visibility:visible;
}
tr:hover .postcell {
visibility:visible;
}
<table>
<tr><td> <div class='precell'>X</div></td><td>blablabla</td><td> <div class='postcell'>[edit]</div></td></tr>
<tr><td> <div class='precell'>X</div></td><td>blablabla</td><td> <div class='postcell'>[edit]</div></td></tr>
<tr><td> <div class='precell'>X</div></td><td>blablabla</td><td> <div class='postcell'>[edit]</div></td></tr>
</table>

Related

Alternating Table Row Color Robust to display:none Settings

I have a dynamic table that I made with javascript. Depending on different user events, some rows will be hidden, rearranged, ect. To be more specific, I'm using display:none; to do this. The issue is the rows always keep their original background color (imagine if all the rows were visible, then you could see the alternating colors). That would be fine if I had the entire table visible, but like I mentioned, sometimes certain rows will be hidden or appear at different positions. This often results in two or more rows of the same color being stacked on top of each other.
There is a similar post:
Alternate table row color even if row is removed
I tried as many of those solutions as I could. However my problem persists. Probably due to the following reasons:
I'm not removing the columns, I'm simply setting display:none;
I'm not working in a jquery environment, so I am limited to native javascript solutions
My code is:
tr:nth-child(even) {
background:gray;
}
tr:nth-child(odd) {
background:lightgray;
}
I have tried tr:nth-of-type(odd) and many similar variants. Is there anything else in CSS or native javascript I can try?
More on Visbility/Selection:
CSS:
tr:not(.selected) {
display: none;
}
JS:
my_circles.each(function(d,i) {
if (my_bool===true) {
d3.select(this).classed('selected',true);
tableRows.get(this).classed("selected", true);
}
});
I'm using d3.js, but I think I will omit the d3 tag, because this seems more of a css or js issue. This is a small snippet, mostly for context, but essentially we should be able to infer the visibility is toggled by a class assignment. If you are curious, it is whenever the user selects a circle on my adjacent scatter plot.
Unfortunately, there is no straight-forward CSS only solution for this problem. Primarily because the :not selector does not go together with nth-... selectors.
Your best bet would be to re-stripe your rows everytime via Javascript.
Stripe your rows as soon as your page is loaded. After that, whenever you change display on any row, you fire your stripe function again.
Here is a crude example:
var tab = document.getElementById("tab"),
btns = tab.getElementsByTagName("a"),
show = document.getElementById("show"),
rows
;
stripe(); // Stripe the rows in beginning
// The stripe function itself
function stripe() {
// select all rows which are not hidden
rows = tab.querySelectorAll('tr:not(.hidden)');
// add a class for every second such row
for(var x = 0; x < rows.length; x++) {
if (x % 2 == 0) { rows[x].classList.add('alt'); }
else { rows[x].classList.remove('alt'); }
}
}
// dummy buttons to hide each row in this demo
[].forEach.call(btns, function(elem) {
elem.addEventListener('click', hide);
});
// your actual code where you hide your rows
function hide(e) {
e.target.parentNode.parentNode.classList.add('hidden');
stripe(); // fire re-striping when hiding rows
}
// dummy button to show rows in this demo
show.addEventListener('click', function(e) {
rows = tab.querySelectorAll('tr.hidden');
[].forEach.call(rows, function(row) {
row.classList.remove('hidden');
});
stripe(); // fire re-striping when showing rows
});
table { width: 70%; border: 1px solid gray; border-collapse: collapse; }
td { border: 1px solid gray; padding: 4px; }
tr.hidden { display: none; }
#tab tr.alt { background-color: #ddd;}
<table id="tab"><tbody>
<tr><td>Row 1</td><td>Hide</td></tr>
<tr><td>Row 2</td><td>Hide</td></tr>
<tr><td>Row 3</td><td>Hide</td></tr>
<tr><td>Row 4</td><td>Hide</td></tr>
<tr><td>Row 5</td><td>Hide</td></tr>
</tbody></table><br />
<a id="show" href="#">Show All</a>
Accompanying fiddle: https://jsfiddle.net/abhitalks/dz5aq5fk/
.
It is not a CSS or native JS solution but here is a d3 based solution. You could change classes of the rows every time the rows in your table change.
d3.selectAll("tr.selected").classed("grey",function(d,i){return i%2 == 0});
It adds the grey class to every second row and removes it from all the rest. Then you can color rows using css.
tr.grey {
background:gray;
}
tr:not(.grey) {
background:lightgray;
}
Here is a jsbin that shows this strategy in action.
this is not a perfect solution, but you can use gradient background in table to get desired result.
below is sample using gradient background in table.
tr:not(.selected) {
display: none;
}
table {
background-color: gray;
background-image: linear-gradient(transparent 50%, lightgray 50%);
background-size: 100% 36px;
}
<table width="500" cellpadding="0" cellspacing="0">
<tr class="selected">
<td>A</td>
<td>B</td>
</tr>
<tr class="selected">
<td>C</td>
<td>D</td>
</tr>
<tr>
<td>E</td>
<td>F</td>
</tr>
<tr class="selected">
<td>G</td>
<td>H</td>
</tr>
<tr>
<td>I</td>
<td>J</td>
</tr>
<tr>
<td>E</td>
<td>F</td>
</tr>
<tr class="selected">
<td>G</td>
<td>H</td>
</tr>
<tr class="selected">
<td>G</td>
<td>H</td>
</tr>
<tr class="selected">
<td>G</td>
<td>H</td>
</tr>
<tr>
<td>I</td>
<td>J</td>
</tr>
</table>
As you correctly pointed out, the reason that the css alternating stripes dont work is that your rows are remaining in place, and just being hidden using display:none.
The trick is to "group" the visible and hidden rows together so that we dont end up with un-event striping. Given that the order of your rows is not important, what we can do is move the hidden rows to either the top (using .insertBefore) or bottom (using .appendChild) of their containing parent. Something similar to this:
my_circles.each(function(d,i) {
if (my_bool===true) {
d3.select(this).classed('selected',true);
var row = tableRows.get(this);
row.parentNode.appendChild(row);
row.classed("selected", true);
}
});

Create a Tooltip Out from arbitrary HTML Table

I am trying to create a tooltip on a web page. I want the user to be able to roll over a link, and when they do, display arbitrary html. In this case, its a simple table, containing some meta data. I have tried using jquery.tools, but I am not sure how to use it correctly. Here is the idea:
<a id="foo">FOO</a>
<div id="tooltip-content">
I am visible when the user hovers over FOO
<table>
<tr>
<td>Name</td>
<td>Foo</td>
</tr>
<tr>
<td>Value</td>
<td>Waka waka</td>
</tr>
....
</table>
</div>
When the user hovers over the link text FOO, I want the div and its content to become visible, floating near the mouse, I don't care if its above, below, left or right of the link text. It just needs to work. What is the simplest / best way to do this? I don't think I can use the title attribute of the link since I want to support an html table, is that correct? How do I do this?
Basic stuff, really. Here's a fiddle: http://jsfiddle.net/MqcMM/. The reason the table and the link are wrapped in a container is to allow hovering over the table once it is displayed.
HTML:
<div id = "container">
<a id="foo" href = "#">FOO</a>
<table>
<tr>
<td>Name</td>
<td>Foo</td>
</tr>
<tr>
<td>Value</td>
<td>Waka waka</td>
</tr>
</table>
</div>
CSS:
body {
padding: 50px;
}
#container {
position: relative;
display: table;
}
#container > table {
position: absolute;
white-space: nowrap;
border-collapse: collapse;
display: none;
}
#container > table td {
border: 1px dotted #000;
padding: 2px;
}
#container:hover > table {
display: table;
}

Force row height in HTML for ng-animation

I have an AngularJS module with a page that shows a table of topics and subtopics. Each topic is a tbody element with 2 rows: one representing the topic name, and one containing a nested table where the rows are the subtopics. Each topic has an expand / collapse button that controls the subtopics, i.e. ng-shows / hides the row where the subtopics table is:
<table>
<tbody ng-repeat="topic in topics">
<tr>
<td>{{topic.name}}</td>
<td class="toggle-subtopics" ng-click="toggleSubtopics(topic)">Expand / collapse</td>
</tr>
<tr class="test-height" ng-show="topic.expanded">
<td colspan=2>
<table>
<tr ng-repeat="subtopic in topic.subtopics">
<td>{{subtopic.name}}</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
I'd like the subtopics row to appear / disappear with ng-animation, but the main problem is that no matter what I do, I can't seem to control the height of this row.
Fiddle
In order to control a td height you need to work on the line-height instead of height
Fiddle
Code Snippet:
.test-height {
line-height: 40px !important; /* This doesn't affect the height of the row */
}
Option 1:
Updated Code:
.table > tbody > tr >td {
line-height: 40px !important;
}
Updated Fiddle Option 1
Option 2:
If you do not want to mess with bootstrap global space you can create your own class and assign that to individual td
Updated Code:
.fixed-height {
line-height: 40px !important;
}
Updated Fiddle Option 2
Try This:
.test-height {
height: 3px;
overflow:hidden;
display:block;
}

Highlighting a dynamically created row

I have a table where a row gets added every time I press a "Add" button. I have an "Edit" button which is placed in the first cell of the newly created row.
I want to highlight the row that is being edited. I know that I can get the current <tr> element like
var par = $(this).parent().parent();
But when I use,
par.css('border-color', 'red');
It does not change the color.
What mistake am I making and how should I highlight that particular row?
This is really about the styling of the <tr>. CSS doesn't like to style <tr>'s because they really only exist for semantics. In order to add a border to one, you need to make it display: block;.
Here is a jsFiddle and example code.
HTML
<table>
<tbody>
<tr><td>Some Content</td></tr>
<tr><td>Some Content</td></tr>
<tr>
<td>
Edit
</td>
</tr>
<tr><td>Some Content</td></tr>
<tr><td>Some Content</td></tr>
</tbody>
</table>
Javascript
$(".edit").click(function(e) {
$(this).closest('tr').toggleClass('editting');
e.preventDefault();
});
CSS
table tr {
display: block;
border: 1px solid rgba(0, 0, 0, 0);
}
.editting {
background: #FAA;
border: 1px solid red;
}
Please note how I used an rgba color to make the border opaque. There are other ways to do this, but if you leave the border off it causes the table to "jitter."
Assuming this refers to an element within the tr, then it will be better to use .closest() here
var par = $(this).closest('tr')

Toggling between CSS display none and display block for a table column creates a weird border... why?

Look at that weird border around the last column in the table...
The table looks like:
<table style="font-family: courier new; font-size: 0.75em" border="1" cellspacing="0" cellpadding="3">
<tbody>
<tr id="tableheader" class="">
<th title="id">id</th>
<th title="old_name">old_name</th>
<th title="new_name">new_name</th>
<th class="edit" title="Edit Options" style="display: block; overflow: hidden;">Edit Options</th>
</tr>
<tr class="tableevenrow">
<td data-col="id" valign="middle" align="left"><div>1</div></td>
<td data-col="old_name" valign="middle" align="left"><div>taco</div></td>
<td data-col="new_name" valign="middle" align="left"><div>bell</div></td>
<td class="edit" data-col="editoptions" valign="middle" align="left" style="display: block; overflow: hidden;">
<div class="row0 col3 col_editoptions">
<div class="edit" style="display: block; overflow: hidden;">
<select id="dropdown_0">
<option value="1">Confirm</option>
<option value="0">Decline</option>
</select>
<button id="submit_r0">Submit</button>
</div>
</div>
</td>
</tr>
and I have buttons that essentially just toggle between these two states:
$('.edit').css('display','none');
$('.norm').css('display','block');
$('.edit').css('display','block');
$('.norm').css('display','none');
So that when anything with the edit class is set to "none" then the whole "edit options" column is not shown at all on the screen. This toggling works. The only problem is that when the edit class is displayed, this column gets a weird border around it. I was wondering if anyone knew why and how to fix it. My buttons toggle visibility with the edit/norm classes below the table (they are in divs) but the border doesn't appear around them...
This is the css for the table styling... which is inherited (kind of) but I need to try and avoid changing this, even dynamically:
body { background: #e8ccbb; }
.tableheader { background: #4d4e86; color: #ffffff; }
.tableoddrow { background: #c2bad4; }
.tableevenrow { background: #c2c3c2; }
#tableheader { background: #4d4e86; color: #ffffff }
#tableoddrow { background: #c2bad4 }
#tableevenrow { background: #c2c3c2 }
#hiliterow { background: #ffffff }
.menu_color {
background:#4d4e86;
background-image:-webkit-gradient(linear,left top,left bottom,from(#c2bad4),to(#4d4e86));
background:-webkit-linear-gradient(top,#c2bad4,#4d4e86);
background:-moz-linear-gradient(top,#c2bad4,#4d4e86);
background:-o-linear-gradient(top,#c2bad4,#4d4e86);
background:-ms-linear-gradient(top,#c2bad4,#4d4e86);
background:linear-gradient(top,#c2bad4,#4d4e86)
}
Also... side note... I am using PHP to make most of this happen and in no way would I describe my self as a front-end developer currently or in the past.... maybe future but who knows.
That's because you're triggering block display, but those should be display: table-cell instead
Best would be to use one button to show and hide the cells using jQuery .toggle(). It`s because you do not have to bother on what was "initial" display of toggling element - jQuery do it for you.
$('#my_button').click(function(){
$('#el_to_toggle').toggle();
});
Implementation:
http://jsfiddle.net/Dr3Cm/
References:
jQuery .toggle()

Categories

Resources