Hello
So I'm trying to make dynamically added rows and when you enter numbers into those rows it should calculate some stuff, the first element that's not appended works fine but the rest isn't getting triggered.
I've tried multiple solutions using $(document).on('keyup change', 'element') and some more.
What I'm trying to achieve is that the calculations should work on every appended row as well.
jsFiddle added
You have few issues in your code.
First of all you do not have the attribute like data-target, row_margin, data-sum set in any of the newly appended element that you are using to find the specific element.
You also have to use delegation approach to attach the event handler which will allow you to fire/raise the event on the elements that are appended dynamically. You can pass this to the function so that you can refer elements only specific to the current table.
$('body').on('input', 'div.list div.list_row table', function(){
CalculateMargin(this);
});
You also do not loop through using .each().
Try the following way:
var offer_rows_i = 2;
$('body').on('input', 'div.list div.list_row table', function(){
CalculateMargin(this);
});
$("div.section_button[data-action='new-offer-row']").click(function(){
$("div.list").append(`<div class="container list_row mt3 w-100 zoomInDown animated fast" data-temp=${offer_rows_i}><table cellspacing="0" cellpadding="0" border="0" width="100%">
<tbody>
<tr>
<td valign="top" align="left" width="9.5%"><input type="text" data-target="row_article" autocomplete="none" /></td>
<td valign="top" align="left" width="17%"><textarea data-target="row_text"></textarea></td>
<td valign="top" align="left" width="10%"><input type="text" data-target="row_quantity" autocomplete="none" value="1" class="numbers" /></td>
<td valign="top" align="left" width="12.5%"><input type="text" data-target="row_price_in" autocomplete="none" value="0,00" /></td>
<td valign="top" align="left" width="12.5%"><input type="text" data-target="row_price_out" autocomplete="none" value="0,00" /></td>
<td valign="top" align="left" width="12.5%"><input type="text" data-target="row_discount" autocomplete="none" class="numbers" /></td>
<td valign="top" align="left" width="12.5%"><input type="text" data-target="row_margin" data-margin="0" data-percentage="0" autocomplete="none" value="0,00 (0%)" readonly="readonly" /></td>
<td valign="top" align="left" width="10%"><input type="text" data-target="row_sum" data-sum="0" autocomplete="none" value="0,00" readonly="readonly" /></td>
<td valign="top" align="center" width="3.5%"><i class="fas fa-times" data-action="delete-row"></i></td>
</tr>
</tbody>
</table></div>`);
offer_rows_i = offer_rows_i + 1;
});
function CalculateMargin(row){
var bruttoCalc = 0;
var summaCalc = 0;
//console.log("changing => " + $(row).data("temp"));
var quantity = $(row).find("input[data-target='row_quantity']").val();
var priceIn = $(row).find("input[data-target='row_price_in']").val();
var priceOut = $(row).find("input[data-target='row_price_out']").val();
var discount = $(row).find("input[data-target='row_discount']").val();
// Row calculations
var tbSumTotal = 0;
var priceInSum = (quantity*priceIn);
var priceOutSum = (quantity*priceOut);
var discountSum = ((priceOutSum/100)*discount);
var totalSum = (priceOutSum-discountSum);
// TB calculations
var tbDiscount = ((quantity*priceOut)*(discount/100));
var tbSum = ((quantity*priceOut)-tbDiscount);
var tbTotal = (tbSum - (quantity*priceIn));
if(!tbTotal || !isFinite(tbTotal)){
tbTotal = 0;
}
tbSumTotal = (tbSumTotal + (tbSum-(quantity*priceIn)));
// Percentage calculations
var marginRawPercentage = (tbTotal/(quantity*priceOut));
var marginPercentage = Math.round(parseFloat(tbTotal/tbSum)*100);
if(!marginPercentage || !isFinite(marginPercentage)){
marginPercentage = 0;
}
// Show results
$(row).find("input[data-target='row_margin']").val(parseFloat(tbSum-(quantity*priceIn)).toFixed(2).replace(".", ",") + " ("+marginPercentage+"%)");
$(row).find("input[data-target='row_sum']").val(parseFloat(priceOutSum-discountSum).toFixed(2).replace(".", ","));
}
div.section_button{
background-color: #ffffff;
width: auto;
float: right;
padding: 8px 12px;
margin: 0 0 0 7px;
border: 1px solid #f2f2f2;
border-radius: 3px;
color: #808080;
font-family: 'Source Sans Pro', sans-serif;
font-size: 9pt;
font-weight: 500;
cursor: pointer;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-ms-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
transition: all 0.2s ease;
}
div.section_button:hover, div.section_button:focus{
outline: none;
background-color: #fbfbfb;
border: 1px solid #ececec;
}
div.section_button.colored{
background-color: #305286;
border: 1px solid #305286;
color: #ffffff;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-ms-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
transition: all 0.2s ease;
}
div.section_button.colored:hover, div.section_button.colored:focus{
outline: none;
background-color: #203b64;
border: 1px solid #203b64;
}
table{
margin: 15px 0 0 0;
}
div.list_row > table{
margin: 0;
}
table thead th{
background-color: #ffffff;
font-family: 'Source Sans Pro', sans-serif;
font-size: 9pt;
font-weight: 600;
color: #404040;
padding: 20px 10px 16px 10px;
border: 1px solid #f2f2f2;
border-left: 0;
border-right: 0;
}
table thead th:first-child{
border-radius: 3px 0 0 3px;
border-left: 1px solid #f2f2f2;
}
table thead th:last-child{
border-radius: 0 3px 3px 0;
border-right: 1px solid #f2f2f2;
}
table thead tr th input[type="checkbox"]{
margin: 2px 0;
padding: 0;
}
div.list_row > table tbody td{
background-color: #ffffff;
font-family: 'Source Sans Pro', sans-serif;
font-size: 9pt;
font-weight: 500;
color: #808080;
padding: 0;
cursor: pointer;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-ms-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
transition: all 0.2s ease;
}
div.list_row > table tbody tr:hover td, div.list_row > table tbody tr:focus td{
background-color: rgba(247, 247, 247, 0.5);
}
div.list_row > table tbody tr td input[type="checkbox"]{
margin: 2px 0;
padding: 0;
}
div.list_row > table tbody tr:last-child td:first-child{
border-radius: 0 0 0 3px;
}
div.list_row > table tbody tr:last-child td:last-child{
border-radius: 0 0 3px 0;
}
div.list_row > table tbody tr td input[type="text"]{
background-color: transparent;
width: calc(100% - 20px);
height: 44px;
border: 0;
padding: 0 10px;
font-family: 'Source Sans Pro', sans-serif;
font-size: 9pt;
font-weight: 500;
color: #606060;
}
div.list_row > table tbody tr td:nth-child(7) input[type="text"]{
background-color: rgba(247, 247, 247, 0.5);
border-left: 1px solid #f2f2f2;
border-right: 1px solid #f2f2f2;
}
div.list_row > table tbody tr td:nth-child(8) input[type="text"]{
background-color: rgba(247, 247, 247, 0.5);
border-left: 0;
border-right: 1px solid #f2f2f2;
}
div.list_row > table tbody tr td textarea{
background-color: transparent;
width: calc(100% - 20px);
height: 18px;
border: 0;
padding: 16px 10px 8px 10px;
font-family: 'Source Sans Pro', sans-serif;
font-size: 9pt;
font-weight: 500;
color: #606060;
resize: none;
}
div.list_row > table tbody tr td i.fas{
margin: 16px 0;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-ms-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
transition: all 0.2s ease;
}
div.list_row > table tbody tr td i.fas:hover{
color: #404040;
}
section#economy div.offer_calc table{
margin: 5px 0 0 0;
padding: 0 0 15px 0;
border-bottom: 1px dotted #ececec;
}
section#economy div.offer_calc table:last-child{
border-bottom: 0;
padding: 0;
}
section#economy div.offer_calc table tr td{
padding: 2px 0;
font-family: 'Source Sans Pro', sans-serif;
font-size: 9pt;
font-weight: 500;
color: #808080;
}
section#economy div.offer_calc table tr td:first-child{
font-weight: 600;
}
section#economy div.offer_calc table:nth-child(3n) tr:last-child td{
padding: 8px 0;
font-weight: 600;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="section_button colored" data-action="new-offer-row"><i class="fas fa-equals"></i> New row</div>
<br /><br />
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<thead>
<tr>
<th valign="top" align="left" width="9.5%">Artikel</th>
<th valign="top" align="left" width="17%">Free text</th>
<th valign="top" align="left" width="10%">Quantity</th>
<th valign="top" align="left" width="12.5%">In price</th>
<th valign="top" align="left" width="12.5%">Out price</th>
<th valign="top" align="left" width="12.5%">Discount %</th>
<th valign="top" align="left" width="12.5%">TB</th>
<th valign="top" align="left" width="10%">Sum</th>
<th valign="top" align="center" width="3.5%"></th>
</tr>
</thead>
</table>
<div class="list">
<div class="container list_row mt3 w-100" data-temp="1">
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tbody>
<tr>
<td valign="top" align="left" width="9.5%"><input type="text" data-target="row_article" autocomplete="none" /></td>
<td valign="top" align="left" width="17%"><textarea data-target="row_text"></textarea></td>
<td valign="top" align="left" width="10%"><input type="text" data-target="row_quantity" autocomplete="none" value="1" class="numbers" /></td>
<td valign="top" align="left" width="12.5%"><input type="text" data-target="row_price_in" autocomplete="none" value="0,00" /></td>
<td valign="top" align="left" width="12.5%"><input type="text" data-target="row_price_out" autocomplete="none" value="0,00" /></td>
<td valign="top" align="left" width="12.5%"><input type="text" data-target="row_discount" autocomplete="none" class="numbers" /></td>
<td valign="top" align="left" width="12.5%"><input type="text" data-target="row_margin" data-margin="0" data-percentage="0" autocomplete="none" value="0,00 (0%)" readonly="readonly" /></td>
<td valign="top" align="left" width="10%"><input type="text" data-target="row_sum" data-sum="0" autocomplete="none" value="0,00" readonly="readonly" /></td>
<td valign="top" align="center" width="3.5%"><i class="fas fa-times" data-action="delete-row"></i></td>
</tr>
</tbody>
</table>
</div>
The problem you asked, that every row you added should be working as well as your first line, which in technical term is that every dynamically added row should also register and trigger the same event as the first fixed row, is rather a simple question. However, your real objective of this table is a bit complicated, in fact this may be a code sample useful to me too:
In first line, by completing at least Quantity, In price, Out price (or maybe you required to input the first 2 columns first), the table should automatically compute and output TB and Sum.
By clicking "New row" button, a new row with same column as the first line should be added into the table
In the new added line, by completing at least Quantity, In price, Out price, the table should automatically compute and output TB and Sum.
Down to your own code now:
Your first row almost works fine, only when some of the case
(input order), your TB and Sum may result NaN, but this is just a
small bug to fix.
The second line you added by clicking the button did not work.
The reason that this happened is because the first row is written in HTML, and when JS $("div.list div.list_row table").on(...) is loaded, it has detected the only row in HTML. And this makes the first row element registered to keyup and change event that calls to CalculateMargin() function.
The second row is added dynamically, and it is not yet register to any event at this point. Therefore, it will not apply CalculateMargin() function.
So in order to make the second row work, all you need to do is to register the row with $("div.list div.list_row table").on(...). This is the simple part.
Debugging method:
If you have Firefox or Chrome to inspect your
code/page, by comparing the two rows of elements, you will find under
Event Listeners, only row one has got change and keyup event
listed, and row two has nothing in it.
Try to replace part of your code:
$("div.list div.list_row table").on('keyup change', function(){
// test if the event is triggered
alert ("altered");
//CalculateMargin();
});
And you will see that by adding a new row, your new row won't pop up this alert message like the first one.
So in your next part of your code:
$("div.section_button[data-action='new-offer-row']").click(function(){
$("div.list").append('<div class="container list_row mt3 w-100 zoomInDown animated fast" data-temp="'+offer_rows_i+'"><table cellspacing="0" cellpadding="0" border="0" width="100%"><tbody><tr><td valign="top" align="left" width="9.5%"><input type="text" data-target="" autocomplete="none"></td><td valign="top" align="left" width="17%"><textarea data-target=""></textarea></td><td valign="top" align="left" width="10%"><input type="text" data-target="" autocomplete="none" value="1"></td><td valign="top" align="left" width="12.5%"><input type="text" data-target="" autocomplete="none" value="0,00"></td><td valign="top" align="left" width="12.5%"><input type="text" data-target="" autocomplete="none" value="0,00"></td><td valign="top" align="left" width="12.5%"><input type="text" data-target="" autocomplete="none"></td><td valign="top" align="left" width="12.5%"><input type="text" data-target="" autocomplete="none" value="0,00 (0%)" readonly="readonly"></td><td valign="top" align="left" width="10%"><input type="text" data-target="" autocomplete="none" value="0,00" readonly="readonly"></td><td valign="top" align="center" width="3.5%"><i class="fas fa-times" data-action="delete-row"></i></td></tr></tbody></table></div>');
offer_rows_i = offer_rows_i + 1;
// register and enable event for new row
$("div.list div.list_row table").on('keyup change', function(){
// test if the event is triggered
alert ("altered");
//CalculateMargin();
});
});
Now both your line applies to your event, with new problem:
Your event **triggered multiple times. Besides your two events change and keyup that causes double trigger, every time you click on "New row" button all the row elements will register to event by code $("div.list div.list_row table").on(...), and it will add to the element event list instead of replacing previous event.
To solve this you will have to clear all pre-registered event and re-register.
Here is the code: 1. Add new row event trigger test
Now you could uncomment your CalculateMargin() to replace the test message alert ("altered").
However, the second line still compute as expected. This is because (like #Qonvex620 #Rob Moll) said, when code processing to var quantity = _this.find("input[data-target='row_quantity']").val(); and so on, the data fetched results undefined.
That is because the code could not find row_quantity here. Check your code in append, you will see <td valign="top" align="left" width="10%"><input type="text" data-target="" autocomplete="none" value="1"></td> where data-target="" means there is no value (row_quantity) for it. This applies to following elements:
row_article
row_text
row_quantity
row_price_in
row_price_out
row_discount
row_margin
row_sum
Here is the final code that works for you: 2. Enable all row cell event
In the html for your first row which is plain-old html you have this:
<td valign="top" align="left" width="9.5%"><input type="text" data-target="row_article" autocomplete="none" /></td>
Notice the Custom Data Attribute named data-target is assigned a value of "row_article".
However, in your dynamic code the CDA named data-target is assigned a value of "".
<td valign="top" align="left" width="9.5%"><input type="text" data-target="" autocomplete="none"></td>
You just need to add the corresponding value in your dynamic code to all of the td's that have this data-target CDA.
Provide a value for your data-target since you are getting input's value through their data-target attached to them.
In you first row it will definitely work because you had provided value on their data-target. like this
<input type="text" data-target="row_price_in" autocomplete="none" value="0,00">
...
...
However in your newly added input, you just put like this without providing any data-target value
<input type="text" data-target="" autocomplete="none" value="0,00>
I have two nested tables. One outer table and inside every row of outer table I have inner table. My problem is when I am filtering using searchBox it filters both the tables outer and inner. I don't want to filter my inner table rows. Look at my problem I don't want my inner table to be filtered.
var $rows = $('#top_table tr');
$('#txtsearch').keyup(function () {
var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
$rows.show().filter(function () {
var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
return !~text.indexOf(val);
}).hide();
});
tr.top_tr td {
border-bottom: 1px solid black;
min-width: 16%;
}
th {
font: bold 11px"Helvetica Neue", Verdana, Arial, Helvetica, sans-serif;
color: #4f6b72;
border-right: 1px solid #C1DAD7;
border-bottom: 1px solid #C1DAD7;
border-top: 1px solid #C1DAD7;
letter-spacing: 2px;
text-transform: uppercase;
text-align: left;
padding: 6px 6px 6px 12px;
background: #CAE8EA url(images/bg_header.jpg) no-repeat;
width: 16%;
}
td {
border-right: 1px solid #C1DAD7;
border-bottom: 1px solid #C1DAD7;
background: #fff;
padding: 0px;
color: #4f6b72;
width: 14%;
}
td:first-child {
border-left: 1px solid #C1DAD7;
}
table {
padding: 0px;
}
#top_table {
padding: 10px;
width: 800px;
}
body {
padding: 10px;
}
.subtable {
width: 100%;
}
.body-td {
border: none;
width: 16%;
}
.collapse {
position: relative;
height: 0;
overflow: hidden;
-webkit-transition: height 0.35s ease;
-moz-transition: height 0.35s ease;
-o-transition: height 0.35s ease;
transition: height 0.35s ease;
display: inline;
width: 100%;
float: left;
}
tr.collapse>td {
display: table;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<input type="text" id="txtsearch" />
<table id="top_table">
<thead>
<tr>
<th>List Name</th>
<th>No. Records</th>
<th>Avail. Records</th>
<th>Creation Date</th>
<th>Last Used</th>
<th>Performance</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="6">
<table class="subtable">
<tbody>
<tr class="top_tr accordion-toggle" data-toggle="collapse" data-parent="#top_table" href="#collapseOne">
<td>LIST NO. 1</td>
<td>30000</td>
<td>3340</td>
<td>05-26-2004</td>
<td>21 days ago</td>
<td>7.3 % TRANSFER RATE</td>
</tr>
<tr >
<td colspan="6">
<table>
<tbody id="collapseOne" class="accordion-body collapse">
<tr>
<td class="body-td" colspan="6">THIS IS A BIG ROW IN A TABLE</td>
</tr>
<tr>
<td class="body-td" colspan="6">THIS IS A BIG ROW IN A TABLE</td>
</tr>
<tr>
<td class="body-td" colspan="6">THIS IS A BIG ROW IN A TABLE</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td colspan="6">
<table class="subtable">
<tbody>
<tr class="top_tr accordion-toggle" data-toggle="collapse" data-parent="#top_table" href="#collapseTwo">
<td>LIST NO. 2</td>
<td>30000</td>
<td>3340</td>
<td>05-26-2004</td>
<td>21 days ago</td>
<td>7.3 % TRANSFER RATE</td>
</tr>
<tr >
<td colspan="6">
<table>
<tbody id="collapseTwo" class="accordion-body collapse">
<tr>
<td class="body-td" colspan="6">THIS IS A BIG ROW IN A TABLE</td>
</tr>
<tr>
<td class="body-td" colspan="6">THIS IS A BIG ROW IN A TABLE</td>
</tr>
<tr>
<td class="body-td" colspan="6">THIS IS A BIG ROW IN A TABLE</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td colspan="6">
<table class="subtable">
<tbody>
<tr class="top_tr">
<td>LIST NO. 3</td>
<td>30000</td>
<td>3340</td>
<td>05-26-2004</td>
<td>21 days ago</td>
<td>7.3 % TRANSFER RATE</td>
</tr>
<tr>
<td colspan="6">THIS IS A BIG ROW IN A TABLE</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
Everyone i got an answer which is very much shocking i just focused on what i actually want and that was just to ignore even rows of table that contains inner tables.
And the answer to this is :var rows= $("tr:odd") and then i applied filteration on these rows .:) Thanks for you precious time.
I have a simple jquery script to highlight DOM element on hover. But this script failed to highlight the rows of my table, there're no problem with cells.
In my script, I need to be able to select any type of elements, not just tables, so I cant't code a solution based on table selection, like DataTables for example. Any suggestions?
$(document).ready(function() {
$("body").on('mouseover', function(event) {
var highlightTarget = $(event.target);
highlightTarget.addClass("highlight");
}).on('mouseout', function(event) {
$(event.target).removeClass('highlight');
});
});
.highlight {
border: 1px solid green;
background-color: darkseagreen;
z-index: 99999;
}
.main {
border-top: 1px solid #9EBACF;
border-bottom: 1px solid #FFFFFF;
border-left: 1px solid #9EBACF;
border-right: 1px solid #FFFFFF;
}
.cat {
border-top: 1px solid #FFFFFF;
border-bottom: 1px solid #9EBACF;
border-left: 1px solid #FFFFFF;
border-right: 1px solid #9EBACF;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="main" cellspacing="0" cellpadding="4">
<tr>
<td class="cat">data 1</td>
<td class="cat">data 2</td>
</tr>
<tr>
<td class="cat">data 3</td>
<td class="cat">data 4</td>
</tr>
<tr>
<td class="cat">data 5</td>
<td class="cat">data 6</td>
</tr>
</table>
One way of doing this using CSS would be to use the :hover selector.
.hoverable:hover {
background: rgba(150, 150, 150, 0.5);
}
All elements of class .hoverable will be highlighted. Note that in the following example, on hovering the first row, both <tr> and <td> are highlighted. In the second row, only the <td> is highlighted, while in the third row, only the <tr> is highlighted.
.hoverable:hover {
background: rgba(180, 180, 180, 0.5);
}
<table class="main" cellspacing="0" cellpadding="4">
<tr class="hoverable">
<td class="hoverable">data 1</td>
<td class="hoverable">data 2</td>
</tr>
<tr>
<td class="hoverable">data 3</td>
<td class="hoverable">data 4</td>
</tr>
<tr class="hoverable">
<td>data 5</td>
<td>data 6</td>
</tr>
</table>
Logic
Bind mouse events on every element.
Create a map for elements where parent is to be considered.
Now, on hover, just check if map has value for this element type.
If yes, fetch parent selector and navigate to it.
If not, use current element as default element.
Remove class from any other element
Add class to stored element.
Note: step 6 is required because, you will have a div. This div will have a table and on till td, but you just want to access current element and not all.
Sample
$(document).ready(function() {
createHover()
});
function createHover() {
const map = {
"TD": "tr"
}
$(document).on('mouseenter mouseout', '*', function(e) {
var myClass = "highlight"
var parent = map[this.nodeName];
var $this = $(this)
var el = $this;
$('.' + myClass).removeClass(myClass)
if (parent) {
el = $this.closest(parent)
}
el.toggleClass(myClass, $this.is(":hover"))
e.stopPropagation()
})
}
.highlight {
border: 1px solid green;
background-color: darkseagreen;
}
.main {
border-top: 1px solid #9EBACF;
border-bottom: 1px solid #FFFFFF;
border-left: 1px solid #9EBACF;
border-right: 1px solid #FFFFFF;
}
.cat {
border-top: 1px solid #FFFFFF;
border-bottom: 1px solid #9EBACF;
border-left: 1px solid #FFFFFF;
border-right: 1px solid #9EBACF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<body>
<table class="main" cellspacing="0" cellpadding="4">
<tr>
<td class="cat">
<strong>Edge case</strong>
</td>
<td class="cat">data 2</td>
</tr>
<tr>
<td class="cat">data 3</td>
<td class="cat">data 4</td>
</tr>
<tr>
<td class="cat">data 5</td>
<td class="cat">data 6</td>
</tr>
</table>
<ul>
<li>This is a test</li>
</ul>
<p>This is also a test</p>
</body>
you don't need JS for that, simple css hover would do it :
.cat:hover{
border: 1px solid green;
background-color: darkseagreen;
z-index: 99999;
}
you dont need .highlight either
i want to make a table header fix to one position and allow the remaining content of table to be scrollable(code below). I am using colspan and rowsapn property in the table header row . Is there any way to fix it ?
<html>
<body>
<div id="secondtable" style="width:100%; height:380px; overflow:auto;">
<table class="mytable" style="width:100%; border-width:thin;" border="1" cellpadding="9" cellspacing="0" align="center">
<tr class="tt" bgcolor="#0B2B62">
<th>No.</th>
<th>Store Name</th>
<th>Receipts</th>
<th colspan=2>Receipts vs Budget</th>
<th colspan=3>Receipts vs Last Year</th>
<th>Contribution</th>
<th colspan=2>Contribution vs Budget</th>
</tr>
<tr class="tt" style="background-color:#C2C2C2;">
<td></td>
<td></td>
<td></td>
<td><font color="black">Var £</font></td>
<td><font color="black">Var %</td>
<td><font color="black">Var £</font></td>
<td><font color="black">Var %</font></td>
<td><font color="black">Var</font></td>
<td></td>
<td><font color="black">Var £</font></td>
<td><font color="black">Var %</font></td>
</tr>
<tr class="tt" style="background-color:#D7F2FF">
<td> </td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</body>
</html>
//this is css
table {
border-collapse:separate;
border-spacing: 0;
color:white;
background-color:white;
border: 1px solid black;
border-radius: 8px;
-moz-border-radius: 5px;
padding: 5px;
font-family:sans-serif;
}
.mytable{
background-color:#014483;
}
.tt{
border-color:#2B4F81;
}
.ttt{
background-color:#BBDBF4;
border:#2B4F81;
}
Question of 3 years old,however for those who still have no solution for this (table head with rowspan) I finally have the methode using js.
<div id="table">
<table>
<thead>
<!-- your head code -->
</thead>
<tbody>
<!-- your body code -->
</body>
</table>
</div>
CSS
#table{
height:200px; //for example
overflow-y:auto;
}
JS
let statusCard = document.querySelector('#table');
// add scroll event listener for change head's position
statusCard.addEventListener('scroll',e =>{
let tableHead = document.querySelector('thead');
let scrollTop = statusCard.scrollTop;
tableHead.style.transform = 'translateY(' + scrollTop + 'px)';
})
You might need to place your header in a div with a class .sticky or whatever you like and a proper CSS.
HTML
<div class="sticky">
<table class="mytable" style="width:100%; border-width:thin;" border="1" cellpadding="9" cellspacing="0" align="center">
<tr class="tt" bgcolor="#0B2B62">
<th>No.</th>
<th>Store Name</th>
<th>Receipts</th>
<th colspan=2>Receipts vs Budget</th>
<th colspan=3>Receipts vs Last Year</th>
<th>Contribution</th>
<th colspan=2>Contribution vs Budget</th>
</tr>
</table>
</div>
CSS
.sticky {
position: fixed;
top: 2px;
width: 96.5%;
}
See the example here: http://codepen.io/omerblink/pen/wMzLow?editors=110
You can use:
.mytable tr th
{
table-layout: fixed;
}
This may help you:
html, body{
margin:0;
padding:0;
height:100%;
}
section {
position: relative;
border: 1px solid #000;
padding-top: 37px;
background: #500;
}
section.positioned {
position: absolute;
top:100px;
left:100px;
width:800px;
box-shadow: 0 0 15px #333;
}
.container {
overflow-y: auto;
height: 200px;
}
table {
border-spacing: 0;
width:100%;
}
td + td {
border-left:1px solid #eee;
}
td, th {
border-bottom:1px solid #eee;
background: #ddd;
color: #000;
padding: 10px 25px;
}
th {
height: 0;
line-height: 0;
padding-top: 0;
padding-bottom: 0;
color: transparent;
border: none;
white-space: nowrap;
}
th div{
position: absolute;
background: transparent;
color: #fff;
padding: 9px 25px;
top: 0;
margin-left: -25px;
line-height: normal;
border-left: 1px solid #800;
}
th:first-child div{
border: none;
}
I doubt you will be able to acheive this with a single table. So I have actually created two tables one for header and another for body & the former is always fixed. Also I assume that number of columns is static. Here is the code
<!--Header part-->
<div id="firsttable" style="width:100%;">
<table class="mytable" style="width:100%; border-width:thin;" border="1" cellpadding="9" cellspacing="0" align="center">
<thead><tr class="tt " bgcolor="#0B2B62">
<th id="no">No.</th>
<th id="sto">Store Name</th>
<th id="res">Receipts</th>
<th colspan=2 id="rb">Receipts vs Budget</th>
<th colspan=3 id="rl">Receipts vs Last Year</th>
<th id="con">Contribution</th>
<th colspan=2 id="cb">Contribution vs Budget</th>
</tr>
</thead>
</table>
</div>
<!-- body part -->
<div id="secondtable" style="width:100%; height:380px; overflow:auto;">
<table class="mytable" style="width:100%; border-width:thin;" border="1" cellpadding="9" cellspacing="0" align="center">
<tr class="tt" style="background-color:#C2C2C2;">
<td headers="no">A</td>
<td headers="sto">B</td>
<td headers="res">C</td>
<td colspan="2" headers="rb"><div style="color:black">Var £</div><div style="color:black">Var %</div></td>
<td colspan="3"><div style="color:black">Var £</div><div>Var %</div><div>Var</div></td>
<td>D</td>
<td colspan="2"><div style ="color:black">Var £</div><div style="color:black">Var %</div></td>
</tr>
<!-- Include multiple tr to get scrollbar -->
</table>
</div>
CSS
table {
border-collapse:separate;
border-spacing: 0;
color:white;
background-color:white;
border: 1px solid black;
border-radius: 8px;
-moz-border-radius: 5px;
padding: 5px;
font-family:sans-serif;
}
.mytable{
background-color:#014483;
}
.tt{
border-color:#2B4F81;
}
.ttt{
background-color:#BBDBF4;
border:#2B4F81;
}
td,th{
max-width:10px;
}
.mytable div{
max-width:40%;
display:inline
}
WORKING COPY
NOTE:When this scrollbar is visible you may see that the header columns is not in sync with body columns. This is because scroll bar has a width and it is will occupy some space.In this case you can adjust the width of any body column so that it is in sync. Also I understand basically you need 7 columns there can be subcolumns. So in body I have created 7 columns and div to replicate the sub columns
Hope this will be helpful
I have a page with two dynamic tables.
When I want to print my page, each of my tables will be separated, one side in one page and other side in other pages. (both tables are dynamic)
I want to make static page break in any 672px
I did many way, but still I didn't get response.
Is there anyway for me?
My HTML:
<table id="selectedTable" style="width: 100%; font-size: 12pt; margin-top: 2px; text-align: right; border-top: 4px solid #000000; border-right: 4px solid #000000;border-left: 4px solid #000000;">
<tr>
<td colspan="{{(TotalDetailsOfUsagesCurrent.length * 2) + 2}}TotalDetailsOfUsagesCurrent">Blah blah</td>
</tr>
<tr>
<td width="53px">
<div style="text-align: center;">Usage</div>
</td>
<td ng-repeat='TDUC in TotalDetailsOfUsagesCurrent track by $index' colspan="2">
{{TDUC.UsageType}}
</td>
<td width="55px" style="border-bottom: 2px solid #000000; border-top: 2px solid #000000; font-size: 12pt;text-align: center; ">
<div>Total</div>
</td>
</tr>
<tr id="selectedRow" ng-click="heightChecker(this)" ng-repeat='DFC in DetailsOfFloorsCurrent'>
<td width=" 53px">
<div dir="ltr"> {{getFloorName(DFC.FloorNo)}} </div>
</td>
<td ng-repeat-start="usage in DFC.Usages track by $index">{{usage.UnitNo}}</td>
<td ng-repeat-end>{{usage.UnitArea}}</td>
<td width="55px">
{{DFC.TotalAreaCurrent.toFixed(2)}}
</td>
</tr>
<tr>
<td>
<div>Total</div>
</td>
<td ng-repeat-start="TDFC in TotalDetailsOfUsagesCurrent">{{TDFC.UnitNo}}</td>
<td ng-repeat-end>{{TDFC.UnitArea.toFixed(2)}}</td>
<td>{{TotalAreaCurrent.toFixed(2)}}</td>
</tr>
</table>
JS:
$scope.heightChecker = function (row) {
selectedRow[row.$index].offsetTop; //it gives me my row distance from top of table. for getting the pixles. but its usless
}