I'm trying to insert dynamic rows in an HTML table. If I comment the line which is supposed to insert dynamic row in the html tag (.innerHTML), the format of the table is fine with the header row on top and the first body row just underneath.
As soon as I uncomment the dynamic row rendering, the dynamic row is created on top of the header row. I cannot find the reason of it. Have a look at the below jsfiddle test code.
html_out = "<tr><td>GRP2</td><td>1</td><td>Team 3</td><td>32000</td><td>Team 4</td></tr>";
document.getElementById("render").innerHTML = html_out;
#scrolltable { margin-top: 20px; height: 150px; overflow: auto; }
#scrolltable table { border-collapse: collapse; }
#scrolltable th div { position: absolute; margin-top: -20px; }
<div id="scrolltable">
<table>
<col width ="50px">
<col width ="60px">
<col width ="120px">
<col width ="100px">
<col width ="120px">
<tr>
<th><div></div></th>
<th><div>Rank</div></th>
<th><div>Squad Name</div></th>
<th><div>Skill Pts</div></th>
<th><div>Current War (vs)</div></th>
</tr>
<tr><td>GRP1</td><td>2</td><td>Team A</td><td>30777</td><td>Team B</td></tr>
<div id="render"></div>
</table>
</div>
Correct table formatting:
Row overlapping header:
https://jsfiddle.net/ShaiHul/0rzqvcbm/60/
Steps to Take for Valid HTML and Accurate DOM Manipulation
Remove .render it's incredibly invalid simply because the only child element <table>/<tbody> can have is <tr>.
You probably resorted to using an dive that way because when using .innerHTML the direct logical way ended up obliterating a portion of the table. .innerHTML overwrites whatever it targets unless you use += instead of = which makes .innerHTML append instead overwrite content.
document.querySelector('table').innerHTML += HTMLString
But there's a method that renders Strings to HTML like .innerHTML but inserts Strings instead overwrites content. Not only is it safer but it's far more accurate.
.insertAdjacentHTML( position, HTMLString )
The first parameter, position is one of four possible String, below is represents a target element to which we intend to place a HTMLString (the second parameter) into or around:
Position: "beforebegin" <table> "afterbegin" ...... "beforeend" </table> "afterend"
Demo
HTMLStr = "<tr><td>GRP2</td><td>1</td><td>Team 3</td><td>32000</td><td>Team 4</td></tr>";
document.querySelector("table").insertAdjacentHTML('beforeend', HTMLStr);
#scrolltable {
margin-top: 20px;
height: 150px;
overflow: auto;
}
#scrolltable table {
border-collapse: collapse;
}
#scrolltable th div {
position: absolute;
margin-top: -20px;
}
<div id="scrolltable"><table><col width="50px"><col width="60px"><col width="120px"><col width="100px"><col width="120px"><tr><th><div></div></th><th><div>Rank</div></th><th><div>Squad Name</div></th><th><div>Skill Pts</div></th><th><div>Current War (vs)</div></th></tr><tr><td>GRP1</td><td>2</td><td>Team A</td><td>30777</td><td>Team B</td></tr></table></div>
You're adding a div to a table, that messes up the layout. You should just insert the HTML into a tr instead of a div and it works fine:
html_out = "<td>GRP2</td><td>1</td><td>Team 3</td><td>32000</td><td>Team 4</td>";
document.getElementById("render").innerHTML = html_out;
#scrolltable { margin-top: 20px; height: 150px; overflow: auto; }
#scrolltable table { border-collapse: collapse; }
#scrolltable th div { position: absolute; margin-top: -20px; }
<div id="scrolltable">
<table>
<col width ="50px">
<col width ="60px">
<col width ="120px">
<col width ="100px">
<col width ="120px">
<tr>
<th><div></div></th>
<th><div>Rank</div></th>
<th><div>Squad Name</div></th>
<th><div>Skill Pts</div></th>
<th><div>Current War (vs)</div></th>
</tr>
<tr><td>GRP1</td><td>2</td><td>Team A</td><td>30777</td><td>Team B</td></tr>
<tr id="render"></tr>
</table>
</div>
If you don't want to rely on having an empty element in the html, you can just get the table and use appendChild() to add another table row to it, e.g.:
var html_out = "<td>GRP2</td><td>1</td><td>Team 3</td><td>32000</td><td>Team 4</td>";
var tr = document.createElement("tr");
tr.innerHTML = html_out;
document.getElementById("table").appendChild(tr);
Related
I have a dynamic table where i have hide after displaying first few words from a big text, if the user want to read the complete data he use to click view more button to read the complete data it works fine but the problem is how to show view more only for the rows which has overflowed text in it.
Php solution
simply in php we can use strlen() and can give condition like
if(strlen($data) > 100 ){
make visible
}
but cant assume how many chars exactly fit in the div because users may use enter so that the text count may vary so it wont works.
JavaScript solution
function checkOverflow(el)
{
var curOverflow = el.style.overflow;
if ( !curOverflow || curOverflow === "visible" )
el.style.overflow = "hidden";
var isOverflowing = el.clientWidth < el.scrollWidth
|| el.clientHeight < el.scrollHeight;
el.style.overflow = curOverflow;
return isOverflowing;
}
here i can find which div is overflowing, but since table was dynamic i don't know the exact ids i tried something like
<tr>
<td>
<div id="hidden_field_{$row['his_id']}">{$row['his_data']}</div>
</td>
<td>
<br/>
<?php
$check_overflow=echo "<script>checkOverflow(document.getElementById('hidden_field_".{$row['his_id']}."'));</script>";
if($check_overflow=="true"){
?>
<a id="get_view_more_{$row['his_id']}" onclick="view_more({$row['his_id'];});">View More</a>
<?php } ?>
</td>
</tr>
this function works fine outside php on the bottom of the page
<script>
alert(checkOverflow(document.getElementById('hidden_field_1')));</script>
you can use ellipsis.
#div2 {
white-space: nowrap;
width: 12em;
overflow: hidden;
text-overflow: ellipsis;
border: 1px solid #000000;
}
#div2:hover {
width: auto;
overflow: visible;
border: 1px solid #000000;
}
<p>This div uses "text-overflow:ellipsis": when you hover this it's visible</p>
<div id="div2">This is some long text that will not fit in the box</div>
just like this way.
I'm using react library that constructs table in the following template:
<div class="table-container" style="width:100%">
<table style="width:100%">
<thead>
<tr>
<th>BLA_Column</th>
</tr>
</thead>
</table>
<table style="width:100%">
<tbody>
<tr>
<td>BLA_Body</td>
</tr>
</tbody>
</table>
</div>
I'm able to set the width of the th and the td to auto, but, the result is that I get two different sizes (one for the th and one for the td).
When I try to use the following selector (for example), nothing happens:
table > thead > th {
width: 100px;
}
Also when I try to change directly the width using the chrome dev-tools, there is no change at all.
Thanks ahead!
CSS character > select only direct childs. Change your CSS with :
table > thead th {
width: 100px;
}
or
table > thead > tr > th {
width: 100px;
}
p {
width: 40px;
margin: 0;
padding: 0;
}
td {
padding: 0;
margin: 0;
}
<table style="width:100px;">
<colgroup>
<col style="width:20px;">
<col style="width:40px;">
<col style="width:40px;">
</colgroup>
<tr>
<th>ID</th>
<th>NAME</th>
<th>Email</th>
</tr>
<tbody>
<tr>
<td>1</td>
<td>john</td>
<td>
<p>johntheman#example.com dsdsdsdsdsd dsdsdsdddddddddddddddddddddddsd dsdsssssssssssssdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsds
sadddddddddddddddddddddddddd
</p>
</td>
</tr>
</tbody>
</table>
I have simple table with fix width. I also have fix width for columns in it to do that I have used CSS colgroup.
Problem 1:
Width of my columns if I check in developer's tool is different than that of what I have given in colgroup.
What I have tried
While fixing it I have found that the width changes with the text in it if I increase the text td increases and vice versa.
Problem 2:
When I enter the text in td unless I don't break it on new line by hitting enter the width of td goes on increasing with text.
What I have tried
To tackle this problem I have wrap my text in a p tag with fix width and then put it in td but still no luck. What I see is width is getting applied to P tag but text is overflowing.
What I expect :
I would like to know that why text is not breaking itself on new line after the fixed width of td. Why text overflows out of P even after fix width? Why td has to increase even after fix width?
I don't know what I am missing to apply here.
for the table use css property
table-layout: fixed;
Then provide fixed with to your td columns.
The width of the <p> tag and <td> are fixed they are not increasing.
Until there is no space in your text content it will not wrap to next line. You have to use ellipsis which will put ... in place of overflowing text content. Use below css for your <p> tag.
p {
width: 40px;
margin: 0;
padding: 0;
text-overflow: ellipsis;
overflow: hidden;
}
I have a dynamic table in my web page that sometimes contains lots of rows. I know there are page-break-before and page-break-after CSS properties.
Where do I put them in my code in order to force page breaking if needed?
You can use the following:
<style type="text/css">
table { page-break-inside:auto }
tr { page-break-inside:avoid; page-break-after:auto }
</style>
Refer the W3C's CSS Print Profile specification for details.
And also refer the Salesforce developer forums.
Wherever you want to apply a break, either a table or tr, you needs to give a class for ex. page-break with CSS as mentioned below:
/* class works for table row */
table tr.page-break{
page-break-after:always
}
<tr class="page-break">
/* class works for table */
table.page-break{
page-break-after:always
}
<table class="page-break">
and it will work as you required
Alternatively, you can also have div structure for same:
CSS:
#media all {
.page-break { display: none; }
}
#media print {
.page-break { display: block; page-break-before: always; }
}
Div:
<div class="page-break"></div>
I have looked around for a fix for this. I have a jquery mobile site that has a final print page and it combines dozens of pages. I tried all the fixes above but the only thing I could get to work is this:
<div style="clear:both!important;"/></div>
<div style="page-break-after:always"></div>
<div style="clear:both!important;"/> </div>
Unfortunately the examples above didn't work for me in Chrome.
I came up with the below solution where you can specify the max height in PXs of each page. This will then splits the table into separate tables when the rows equal that height.
$(document).ready(function(){
var MaxHeight = 200;
var RunningHeight = 0;
var PageNo = 1;
$('table.splitForPrint>tbody>tr').each(function () {
if (RunningHeight + $(this).height() > MaxHeight) {
RunningHeight = 0;
PageNo += 1;
}
RunningHeight += $(this).height();
$(this).attr("data-page-no", PageNo);
});
for(i = 1; i <= PageNo; i++){
$('table.splitForPrint').parent().append("<div class='tablePage'><hr /><table id='Table" + i + "'><tbody></tbody></table><hr /></div>");
var rows = $('table tr[data-page-no="' + i + '"]');
$('#Table' + i).find("tbody").append(rows);
}
$('table.splitForPrint').remove();
});
You will also need the below in your stylesheet
div.tablePage {
page-break-inside:avoid; page-break-after:always;
}
this is working for me:
<td>
<div class="avoid">
Cell content.
</div>
</td>
...
<style type="text/css">
.avoid {
page-break-inside: avoid !important;
margin: 4px 0 4px 0; /* to keep the page break from cutting too close to the text in the div */
}
</style>
From this thread: avoid page break inside row of table
When converting to PDF with SelectPdf I couldn't get a group of rows to stay together. Tried to put them in a <div style="break-inside: avoid;"> but that didn't work.
Nothing was working until I found this: https://stackoverflow.com/a/27209406/11747650
Which made me rethink my logic and place the things I didn't want to split inside a <tbody>.
<table>
<thead style="display: table-header-group;">
<tr>
<th></th>
</tr>
</thead>
-- Repeating content --
<tbody style="break-inside: avoid;">
-- First row from group --
<tr>
<td> Only shown once per group </td>
</tr>
-- Repeating rows --
<tr>
<td> Shown multiple times per group </td>
</tr>
</tbody>
This results in a table that has multiple <tbody> but that's something that is completely fine as many people use this exact pattern to group together rows.
If you know about how many you want on a page, you could always do this. It will start a new page after every 20th item.
.row-item:nth-child(20n) {
page-break-after: always;
page-break-inside: avoid;
}
I eventually realised that my bulk content that was overflowing the table and not breaking properly simply didn't even need to be inside a table.
While it's not a technical solution, it solved my problem to simply end the table when I no longer needed a table; then started a new one for the footer.
Hope it helps someone... good luck!
Here is an example:
Via css:
<style>
.my-table {
page-break-before: always;
page-break-after: always;
}
.my-table tr {
page-break-inside: avoid;
}
</style>
or directly on the element:
<table style="page-break-before: always; page-break-after: always;">
<tr style="page-break-inside: avoid;">
..
</tr>
</table>
We tried loads of different solutions mentioned here and elsewhere and nothing worked for us. However we eventually found a solution that worked for us and for us it seems to somehow be an Angular issue. I don't understand why this works, but for us it does and we didn't need any page break css in the end.
#media print {
ng-component {
float: left;
}
}
So just hoping this helps someone else as it took us days to fix.
You should use
<tbody>
<tr>
first page content here
</tr>
<tr>
..
</tr>
</tbody>
<tbody>
next page content...
</tbody>
And CSS:
tbody { display: block; page-break-before: avoid; }
tbody { display: block; page-break-after: always; }
Made a table for a product listings page that has a row of 3 images, then a row of text below each image, then repeat. Rather than have the page scroll down indefinitely, I figure it would be better to use some JS/jQuery to change the values in each < td > (img & matching text) than to create a new page for every 6 products. However, my kindergarten-level JS is failing me miserably.
While I think the question I'm asking above is pretty obvious, I'm also wondering if this never should have been set up as a table in the first place. It seemed like the easiest way to keep it organized, but the few examples I've seen seem to do this with < div >'s rather than tables.
Here's a JSFiddle I was messing around with: http://jsfiddle.net/jshweky/FgVY2/
HTML:
<table id="saladGrid">
<tr class="saladPics">
<td class="s1"></td>
<td class="s2"></td>
<td class="s3"></td>
</tr>
<tr class="saladTxt">
<td class="txt">
<p>acorn squash, golden beets, pistachios</p>
</td>
<td class="txt">
<p>roasted eggplant, herbed ricotta, sumac</p>
</td>
<td class="txt">
<p>arugula, fennel, blackberries, quinoa, pickled shallots</p>
</td>
</tr>
<tr class="saladPics">
<td class="s4"></td>
<td class="s5"></td>
<td class="s6"></td>
</tr>
<tr class="saladText">
<td class="text">
<p>arugula, orange, golden beets, golden tomatoes, pistachios</p>
</td>
<td class="text">
<p>caesar</p>
</td>
<td class="text">
<p>butternut squash, lime, feta, chili</p>
</td>
</tr>
</table>
<button id="prev">Prev</button>
<button id="next">Next</button>
CSS (paraphrased):
table {
width: 100%;
height: 100%;
margin-top: 0;
padding: 0;
border: 0;
border-spacing: 0;
}
td {
margin: 0;
padding: 0;
border: 0;
text-align: center;
vertical-align: middle;
}
#saladGrid table {
margin: 0 auto;
border-spacing: 30px;
}
.saladPics td {
height: 350px;
width: 350px;
background-position: center;
background-size: 415px 400px;
background-repeat: no-repeat;
border-radius: 250px;
border: 1px black solid;
}
.saladText {
position: relative;
margin-bottom: -20px;
}
.saladPics td.s1 {
background-image: url("http://i1281.photobucket.com/albums/a514/jshweky/Gourmade%20to%20Order/IMG_1989_zps38d802a7.jpg");
}
I figure it's a matter of creating new var's and writing a function to add 6 to the existing img class (e.g. s1 becomes s7, etc.) but that's just a guess and as I said, even if that's right I'm still in the embryonic stages of JS coding.
Your JavaScript to Swap the image works fine, the issue is the first part of your script. I commented it out in the fiddle and it worked fine. There are definitely better ways to do this (sliding DIVs inside a container, build elements in javascript and append them to the frames on the page - this would give you almost a pinterest style effect of loading new elements at the bottom) - it all depends on how you want to handle it but my suggestion would be to look into using jQuery to add or remove elements to the DOM.
//var s7= new image();
//img.src=url('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRHC9Vk1U5yC5RWMhUK9Ai2RGIDCSh-wxPt-aleQm9onxi9xbN9dA');
$(document).ready(function () {
$('#prev').click(function () {
$('.s1').css('background-image', 'url("http://i1281.photobucket.com/albums/a514/jshweky/Gourmade%20to%20Order/IMG_1483_zpsc4ca87cf.jpg")');
});
});
Also, here is an alternate syntax for the .css() that will let you change more than one property of an elements at a time (you will need to use the .html() function to change the text in the following element too):
$('.s1').css({backgroundImage : 'url("http://i1281.photobucket.com/albums/a514/jshweky/Gourmade%20to%20Order/IMG_1483_zpsc4ca87cf.jpg")', backgroundSize : "cover"}); });