I have done extensive Google searches and implemented a number of solutions found here at stack overflow and at other sites but have not been able to get my table to scroll under program control.
I am implementing a scrolling table of variable names to use in a plot. I have 200+ variables so I want users to be able to type some fragment of a variable's name and show that variable in the list by scrolling. I have this all working except the scrolling part.
This is what a table looks like:
http://www.oceanatlas.com/images/list1.png
This is the HTML that defines the table:
<div id="ySeriesParamChooser" class="ParamChooser">
<table id="yparamtable" cellspacing="0" border="1" >
<thead class="fixedHeader">
<tr>
<th colspan="3">Primary Y Axis</th>
</tr>
</thead>
<tbody class="scrollContent" style="text-align: center;">
<tr>
<td>Cell Content 1</td>
<td>Cell Content 2</td>
<td>Cell Content 3</td>
</tr>
</tbody>
</table>
</div>
I create the contents of the table programatically using Javascript. As you can see from the image link above the table looks and functions as I designed.
Here is the some relevant CSS:
html>body tbody.scrollContent {
display: block;
height: 193px;
overflow: auto;
table-layout: fixed;
font-family: Helvetica, Palatino, Arial, sans-serif;
font-size: 0.8em;
width: 100%
}
.ParamChooser {
padding: 0px 10px 0px 0px;
float:left;
font-family: Droid Sans, Arial, Helvetica, sans-serif;
font-size: .8em;
cursor:default;
}
What I have tried:
// this code correctly find the nth <tr> in the table
var symTarg = "#" + this.jqSel ;
var row = $(symTarg).find('tr').eq(n);
row.scrollIntoView(); // this doesn’t do anything
// this didn’t do anything
var scrollTarg = "#" + this.jqSel + “.scrolltable"; // jqSel == "yparamtable"
var row = $(symTarg).find('tr').eq(n);
if (row.length) {
$(scrollTarg).scrollTop(row.offset().top - ($(scrollTarg).height()/2));
}
// tried this to see if I could just scroll to the last row
var symTarg = "#" + this.jqSel ; // jqSel == "yparamtable"
var rowpos = $(symTarg).find('tr:last').position(); // finds last <tr>
var content = $(symTarg).find('tbody.scrollcontent');
$(content).scrollTop(rowpos.top);
So, what am I doing wrong? I am an experienced programmer but new to UI programming in Javascript.
Here is a fiddle of the scrolling working : https://jsfiddle.net/070vx0oo/7/
First, in order to scroll to a specific element, you have to select only the element and not its parent, to get its position :
var rowpos = $('.scrollContent > tr:eq(4)').position(); // finds the 5th <tr> child of .scrollContent
Here the elements are the TRs. The position is relative to the first parent, which is .scrollContent (tbody)
Then, we need to scroll INTO this parent. So we select .scrollContent which is the parent we are talking about, and use scrollTop().
var content = $('.scrollContent');
$(content).scrollTop(rowpos.top);
So we scroll to the position of our TD.
Also note that I had to add this CSS to our parent (remember, the one called .scrollContent) so that we can scroll into it.
.scrollContent{
display:block; /* Allows us to resize the element */
overflow: auto; /* Automatically adds scrollbars if content overflows */
height:100px; /* Our custom table height */
position:relative; /* Important ! so javascript get accurate position */
}
Now you just have to implement it in your own JavaScript, by selecting the correct TR for var rows.
I hope it helped you to understand.
Related
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);
}
});
If my code looks like this:
<table>
<td class="noprint">1</td>
<td class="noprint">2</td>
<td class="print">3</td>
<td class="noprint">4</td>
<td class="noprint">5</td>
<td class="print">6</td>
<td class="noprint">7</td>
<td class="noprint">8</td>
<td class="print">9</td>
</table>
And I would like to open a new window with javascript to print only elements with a class="print", how do I do that? Tnx.
You've said in a comment that you want to:
"open a new window and "pass" elements with class "print" to that page"
You can clone your table, remove any cells that aren't class="print", get the HTML for that, and write it out to the new window:
var clone = document.querySelector("selector for your table").cloneNode(true);
var list = clone.querySelectorAll("td:not(.print)");
var i;
for (i = 0; i < list.length; ++i) { // QSA returns static lists, so we can loop normally
list[i].parentNode.removeChild(list[i]);
}
var wnd = window.open();
wnd.document.write("<!doctype html><html><title>Something Appropriate</title></head><body></body></html>");
wnd.document.close();
wnd.document.body.innerHTML = clone.outerHTML
Live Example
But note that most of the time, this isn't necessary. If your main window has #media screen and #media print rules, you can manage what's shown vs. what's printed right there in the main window, without having to open a new one.
Example - CSS:
table {
border-collapse: collapse;
border: 1px solid #aaa;
}
td {
padding: 2px;
border: 1px solid #aaa;
}
#media screen {
.print-only {
display: none;
}
}
#media print {
.screen-only {
display: none;
}
}
HTML:
<table>
<tbody>
<tr>
<td class="screen-only">Screen Only</td>
<td class="print-only">Print Only</td>
<td>Either print or screen</td>
</tr>
</tbody>
</table>
Live Copy
Note that when you're viewing the page on-screen, you see "Screen Only" and "Either print or screen" cells, but when you print (or view a print preview), you see "Print Only" and "Either print or screen" cells.
It's very powerful, and doesn't require any script.
You need to make a css and give media = "print", something like this:
<link rel="your path" media="print">
/* define these properties into css file: */
.noprint{display: none;}
.print{display: block;}
It will work.
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;
}
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;
}
I did some research and found that the only way to vertically center a table inside a div(where the table does not span the full height, the height varies with varying content) is with javascript/jquery:
<script>
var tableMarginTop = Math.round( (testHeight - tableHeight) / 2 );
$('table').css('margin-top', tableMarginTop)
</script>
Now my code looks like this:
CSS:
.rightDiv{
width: 300px
height: 380px;
background: url(http://myimage.com) no-repeat;
}
.rightDiv table{
margin: auto; /*For centering horizontally*/
}
HTML:
<div class="rightDiv">
<table width="80%">
<tr><td></td></tr>
</table>
</div>
My question: How to I implement that code for this situation? Not sure how to call the specific div class and table class in the JS function for the relevant div and table?
Thank You
Hoping I have understood your question correctly - how about this example? http://jsfiddle.net/9Zg8a/1/
<div style="height:200px; vertical-align:middle; display:table-cell; border:green 1px solid">
<table style="border:red 1px solid">
<tr>
<td>test text
</td>
</tr>
</table>
</div>
This answer is for the question:
My question: How to I implement that code for this situation? Not sure how to call the specific div class and table class in the JS function for the relevant div and table?
".rightDiv" and ".rightDiv table" at your sample offers nothing! Make it simpler.
CSS
#rightDiv{
width: 300px
height: 380px;
background: url(http://myimage.com) no-repeat;
}
#rightDivTable{
margin: auto; /*For centering horizontally*/
}
HTML
<div id="rightDiv">
<table id="rightDivTable" width="80%">
<tr><td></td></tr>
</table>
</div>
UPDATE: added missing quotes and requested code
This way you will use $('#rightDiv') and $('#rightDivTable') in jquery for your elements.
JS
var
testHeight = $('#rightDiv').innerHeight(),
tableHeight = $('#rightDivTable').outerHeight(),
tableMarginTop = Math.round( (testHeight - tableHeight) / 2 );
$('#rightDivTable').css('margin-top', tableMarginTop);
This way you can center a table in a div. By setting margin-left and margin-right to auto you can center pretty much every object.
<div style="300px; height: 380px">
<table style="margin-left:auto; margin-right:auto">
<tr>
<td>
...
</td>
</tr>
</table>
</div>
how about this-
<div class="rightDiv">
<center><table width="80%">
<tr><td></td></tr>
</table></center>
</div>
center is not recommended for use but what is the problem in using it.
Update-
i can't assign it center without dimensions.
There may be other ways of centering vertically, but if you want to stick with script, here's one way of doing it - jsfiddle here:
var testHeight = $('.rightDiv').innerHeight();
var tableHeight = $('.rightDiv table').outerHeight();
var tableMarginTop = Math.round( (testHeight - tableHeight) / 2 );
$('table').css('margin-top', tableMarginTop)
JQuery lets you use CSS-style selectors for referencing elements, so you can use your existing classes and refer to them in the same way that the CSS does. Or you can assign IDs and use $('#idgoeshere') instead - and perhaps update the CSS also to use id-based selectors.
Using IDs can be faster, since JQuery can internally optimize the selector query to use document.getElementById. (One common benefit to using class-based selectors is that you can operate on a set of matching elements all in one go - though this doesn't work in your specific case if the tables have differing heights.)