Manipulating <td>'s within different <tr>'s - javascript

I'm wondering if the following can be done.
I have a list of 'expenses' that I'm displaying in a table. 4 columns - amount, date, where, and what.
I was thinking I'd like to make each clickable via jQuery which would expand that particular expense, inline, to show a more detailed description.
What I'm trying to do is, on click, replace the contents of the 'tr' with a single 'td' that would contain the extended info. Problem is that 'td' only expands to about a quarter of the table. Is there any way of making it extend to the whole row, while maintaining the widths of the other 'td's in the other rows?

Here's what I would do. Working Demo.
<table id="expenses">
<thead>
<tr>
<td>Amount</td>
<td>Date</td>
<td>Where</td>
<td>What</td>
</tr>
</thead>
<tbody>
<tr class='expense' id='expense-1'>
<td>$5.99</td>
<td>4/2/2009</td>
<td>Taco Bell</td>
<td>Chalupa</td>
</tr>
<tr class='details' id='details-1'>
<td colspan='4'>
It was yummy and delicious
</td>
</tr>
<tr class='expense' id='expense-2'>
<td>$4.99</td>
<td>4/3/2009</td>
<td>Burger King</td>
<td>Whopper</td>
</tr>
<tr class='details' id='details-2'>
<td colspan='4'>
The king of burgers, indeed!
</td>
</tr>
<tr class='expense' id='expense-3'>
<td>$25.99</td>
<td>4/6/2009</td>
<td>Olive Garden</td>
<td>Chicken Alfredo</td>
</tr>
<tr class='details' id='details-3'>
<td colspan='4'>
I love me some italian food!
</td>
</tr>
</tbody>
</table>
With styles like these:
#expenses tr.expense {
cursor: pointer;
}
#expenses tr.details {
display: none;
}
And then have Javascript that looks like this:
$(function() {
$('tr.expense', '#expenses').click(function() {
var id = $(this).attr('id').split('-').pop();
var details = $('#details-'+id);
if(details.is(':visible')) {
details.hide();
} else {
details.show();
}
});
});
That should do it.

<td colspan="4"> ?

Related

How to reference a data attribute of another element?

I am trying to create a responsive table, that collapses from a horizontal to a vertical layout. For that I use a :before pseudo-element, that gets its value from a data attribute. Consider the following dom-structure:
td:before {
content: attr(data-th);
}
<table>
<thead>
<tr>
<th>First</th>
<th>Second</th>
<th>Third</th>
<th>Fourth</th>
</tr>
</thead>
<tbody>
<tr>
<td data-th="First">Alpha</td>
<td data-th="Second">Beta</td>
<td data-th="Third">Gamma</td>
<td data-th="Fourth">AnotherGreekLetter</td>
</tr>
</tbody>
</table>
This works fine and well, until you realize, that you have to write every single data-attribute by hand, since every new row of data requires the data-attribute.
Ideally I would like to have something like this:
td:before:nth-of-type(4n+1) {
content: attr(data-th:nth-of-type(4n+1));
}
td:before:nth-of-type(4n+2) {
content: attr(data-th:nth-of-type(4n+2));
}
<table>
<thead>
<tr>
<th data-th="First">First</th>
<th data-th="Second">Second</th>
<th data-th="Third">Third</th>
<th data-th="Fourth">Fourth</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alpha</td>
<td>Beta</td>
<td>Gamma</td>
<td>AnotherGreekLetter</td>
</tr>
</tbody>
</table>
where I am referencing the data-attribute of the th-nodes.
Now, as far as I know, there is no way of walking the dom-tree with just css, so I assume this would only be possible with javascript. Yet, I have never made use of the data-attribute, so I am hoping that I am wrong about that.
Can I make this work with (in descending order of preference): only css, php, javascript?
Don't think you can do this via CSS, you could probably use a slightly different approach if using jQuery too as you could use an ID to locate the values from the header and write it out to the body e.g.
<table>
<thead>
<tr data-id="1">
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
</tr>
</thead>
<tbody>
<tr data-id="1"></tr>
</tbody>
</table>
And the jQuery:
$(document).ready(function() {
$("thead tr th").each(function( index ) {
$("tbody tr[data-id='" + $(this).parent().attr('data-id') + "']").append('<td>' + $(this).text() + '</td>');
});
});
http://codepen.io/anon/pen/kXdkyY
Hopefully this gives you an alternative idea of how you could loop through and grab data in a different way.

Infinite scroll on table with merged cells (defined colspan/rowspan)

How can I implement the infinite scroll on a table with the merged cells?
I want to implement pivot grid with lots of data to be processed. The difficulty is drawing only visible parts of headers (+ scrolling buffer).
Possible solutions:
Without smooth scrolling, discretely, redraw all table header. (I would like smoothness)
Implement the div-table and organize creating and deleting items on scroll event. (Could not find an example of a dynamic div-table with the merged cells)
Implement the table header from the sequence of tables, that created and removed as necessary. (delete borders, share labels between the nearby tables)
Example:
var xHeaderWrapperEl = document.querySelector(".header-wrapper");
var xHeaderTableEl = document.querySelector(".header-table");
xHeaderWrapperEl.addEventListener("scroll", function () {
if (xHeaderWrapperEl.scrollLeft >= xHeaderTableEl.offsetWidth - xHeaderWrapperEl.offsetWidth){
console.log("scroll next page");
} else if (xHeaderWrapperEl.scrollLeft <= 0) {
console.log("scroll prev page");
} else {
console.log("scroll");
}
});
.header-wrapper {
overflow-x: scroll;
width: 250px;
height: auto;
display: flex;
//flex-flow: row nowrap;
}
<body>
<div class="header-wrapper">
<!-- 1st block -->
<table class="header-table" border="1">
<tr>
<td colspan="10"><div>0x1</div></td>
</tr>
<tr>
<td colspan="2"><div>1x1</div></td>
<td colspan="8" rowspan="2"><div>1x2</div></td>
</tr>
<tr>
<td colspan="2"><div>2x1</div></td>
</tr>
<tr>
<td><div>3x1</div></td>
<td><div>3x2</div></td>
<td><div>3x3</div></td>
<td><div>3x4</div></td>
<td><div>3x5</div></td>
<td><div>3x6</div></td>
<td><div>3x7</div></td>
<td><div>3x8</div></td>
<td><div>3x9</div></td>
<td><div>3x10</div></td>
</tr>
</table>
<!-- 2nd block -->
<table class="header-table" border="1">
<tr>
<td colspan="4"><div>0x1</div></td>
<td colspan="6"><div>0x2</div></td>
</tr>
<tr>
<td colspan="4" rowspan="2"><div>1x1</div></td>
<td colspan="6"><div>1x2</div></td>
</tr>
<tr>
<td colspan="6"><div>2x1</div></td>
</tr>
<tr>
<td><div>3x1</div></td>
<td><div>3x2</div></td>
<td><div>3x3</div></td>
<td><div>3x4</div></td>
<td><div>3x5</div></td>
<td><div>3x6</div></td>
<td><div>3x7</div></td>
<td><div>3x8</div></td>
<td><div>3x9</div></td>
<td><div>3x10</div></td>
</tr>
</table>
<!-- 3rd block -->
<table class="header-table" border="1">
<tr>
<td colspan="2"><div>0x1</div></td>
<td colspan="6"><div>0x2</div></td>
<td colspan="2"><div>0x3</div></td>
</tr>
<tr>
<td colspan="2"><div>1x1</div></td>
<td colspan="2"><div>1x2</div></td>
<td colspan="2"><div>1x3</div></td>
<td colspan="2"><div>1x4</div></td>
<td colspan="2"><div>1x5</div></td>
</tr>
<tr>
<td colspan="2"><div>2x1</div></td>
<td colspan="2"><div>2x2</div></td>
<td colspan="2"><div>2x3</div></td>
<td colspan="2"><div>2x4</div></td>
<td colspan="2"><div>2x5</div></td>
</tr>
<tr>
<td><div>3x1</div></td>
<td><div>3x2</div></td>
<td><div>3x3</div></td>
<td><div>3x4</div></td>
<td><div>3x5</div></td>
<td><div>3x6</div></td>
<td><div>3x7</div></td>
<td><div>3x8</div></td>
<td><div>3x9</div></td>
<td><div>3x10</div></td>
</tr>
</table>
</div>
</body>
Take note flexbox...
I am assuming that you will have 1mln columns table according to your answer.
It is not realistic to have such a table continuously scrollable.
It will take forever to scroll/find/consume information from there.
Therefore you have to have some pagination / filtering mechanism there.
And with the pagination your problem is less severe. Split it in partial table blocks wrapped in scrollable page container. So you will have scrollable pages similar to gmail's message list - paginated yet scrollable.

Ng-repeat is not working as expected in html table?

Why doesn't this simple table structure work in angularjs? None of the rows gets populated with the data. If I replace span with tr, it works fine but my third column of Percent doesn't fit in well.
<table class="table table-hover">
<tbody>
<tr>
<th>Grade</th>
<th>Point</th>
<th>Percent</th>
</tr>
<tr>
<span ng-repeat="gdata in gradepoints">
<td ng-repeat="(grade, gp) in gdata"> {{grade | uppercase}} </td>
<td ng-repeat="(grade, gp) in gdata"> {{gp}} </td>
</span>
<span ng-repeat="pdata in percents">
<td ng-repeat="(grade, perc) in pdata"> {{perc}} </td>
</span>
</tr>
</tbody>
</table>
Try this:
<tr ng-repeat="gdata in gradepoints">
<td>{{gdata.grade | uppercase}}</td>
<td>{{gdata.gp}}</td>
<td>{{pdata[$index].perc</td>
</tr>
You want one row for each element in the gdata array, so the ng-repeat needs to be on the <tr> element. If the two arrays aren't in sync, you can create a function in your controller to return the pdata element you need:
$scope.findPdata(gdata, index) {
// ... do your magic here to find the pdata element you want
return result;
}
<td>{{findPdata(gdata, $index)}}</td>
guessing from the below:
<tr>
<th>Grade</th>
<th>Point</th>
<th>Percent</th>
</tr>
i guess your table has 3 columns so your each row has 3 columns?
in that case use the following
<tr ng-repeat="gdata in gradepoints">
<td>{{gdata.grade | uppercase}}</td>
<td>{{gdata.gp}}</td>
<td>{{gdata.percent}}</td>
</tr>
for above to work your gradepoints must be an ARRAY containing objects with 3 properties each i.e. grade,gp,percent

how to merge 2 rows together WITH 2 rows in html table?

I am not so good in English, to express myself, so I show it with examples to you!
Here is my HTML table with code:
<table border="1">
<tr id="tr1_1">
<td rowspan="2">1</td>
<td>tr1.1 td2</td>
<td>tr1.1 td3</td>
<td rowspan="2">
up/
down
</td>
</tr>
<tr id="tr1_2">
<td>tr1.2 td2</td>
<td>td1.2 td3</td>
</tr>
<tr id="tr2_1">
<td rowspan="2">2</td>
<td>tr2.1 td2</td>
<td>tr2.1 td3</td>
<td rowspan="2">
up/
down
</td>
</tr>
<tr id="tr2_2">
<td>tr2.2 td2</td>
<td>td2.2 td3</td>
</tr>
</table>
(You can see the result here)
For example, if I click on the second two rows' "up" link, the result should be this:
<table border="1">
<tr id="tr2_1">
<td rowspan="2">2</td>
<td>tr2.1 td2</td>
<td>tr2.1 td3</td>
<td rowspan="2">
up/
down
</td>
</tr>
<tr id="tr2_2">
<td>tr2.2 td2</td>
<td>td2.2 td3</td>
</tr>
<tr id="tr1_1">
<td rowspan="2">1</td>
<td>tr1.1 td2</td>
<td>tr1.1 td3</td>
<td rowspan="2">
up/
down
</td>
</tr>
<tr id="tr1_2">
<td>tr1.2 td2</td>
<td>td1.2 td3</td>
</tr>
</table>
(You can see the final result here)
So how could I do this? I know the prev() and before() methods in javascript, but it merge only 1 row with 1 row, but I want to merge 2 rows WITH 2 rows!
I hope, someone can help me! Thank you!
Try this jQuery code :
$('.up').click(function() {
tr = $('tr[id^="'+$(this).closest('tr').attr('id').slice(0, 3)+'"]')
tr.insertBefore(tr.eq(0).prev().prev())
return false;
})
$('.down').click(function() {
tr = $('tr[id^="'+$(this).closest('tr').attr('id').slice(0, 3)+'"]')
tr.insertAfter(tr.eq(1).next().next())
return false;
})
And have a look to your fiddle edited : http://jsfiddle.net/lulu3030/UQz8u/6/
Just some explanations :
closest('tr') method find the nearest parent which has a tr tag
slice(0, 3) get the first 3 characters of a string
=> variable tr selects all elements which has the same 3 first id characters
insertBefore and insertAfter methods allows to move selected elements
Could be done like that too:
DEMO
$(function () {
$('.up, .down').on('click', function () {
var $tr = $(this).closest('tr'),
$flag = $('<tr/>').insertBefore($tr),
$rows = $tr.add($tr.next('tr')).detach()
methods = $(this).is('.up') ? ['insertBefore', 'prevAll'] : ['insertAfter', 'nextAll'];
if ($flag[methods[1]]('tr').eq(1).length) {
$rows[methods[0]]($flag[methods[1]]('tr').eq(1));
$flag.remove();
} else $flag.replaceWith($rows);
});
});

jQuery or JS transformation of dynamic HTML table

I need to find a TABLE within a DIV tag and perform modifications on the header. The available reporting tool does not allow to identify the generated table but allows script and DIV insertion.
Consider the table below where the header is the first line:
<div id="ScrollHeader">
<table>
<tr>
<td>Browser</td>
<td>Visits</td>
<td>Pages/Visit</td>
<td>Avg. Time on Site</td>
<td>% New Visits</td>
<td>Bounce Rate</td>
<td>Avg. Time on Site</td>
<td>% New Visits</td>
<td>Bounce Rate</td>
</tr>
<tr>
<td>Firefox first</td>
<td>1,990</td>
<td>3.11</td>
<td>00:04:22</td>
<td>70.00%</td>
<td>32.61%</td>
<td>00:04:22</td>
<td>70.00%</td>
<td>32.61%</td>
</tr>
<tr>
<td>Firefox</td>
<td>1,990</td>
<td>3.11</td>
<td>00:04:22 test test test</td>
<td>70.00%</td>
<td>32.61%</td>
<td>00:04:22</td>
<td>70.00%</td>
<td>32.61%</td>
</tr>
</table>
</div>
I need a JavaScript or jQuery code to transform the table to the following:
<div id="ScrollHeader">
<table>
<thead>
<tr>
<th>Browser</th>
<th>Visits</th>
<th>Pages/Visit</th>
<th>Avg. Time on Site</th>
<th>% New Visits</th>
<th>Bounce Rate</th>
<th>Avg. Time on Site</th>
<th>% New Visits</th>
<th>Bounce Rate</th>
</tr>
</thead>
<tr>
<td>Firefox first</td>
<td class="numeric">1,990</td>
<td class="numeric">3.11</td>
<td class="numeric">00:04:22</td>
<td class="numeric">70.00%</td>
<td class="numeric">32.61%</td>
<td class="numeric">00:04:22</td>
<td class="numeric">70.00%</td>
<td class="numeric">32.61%</td>
</tr>
</table>
</div>
The code needs to identify the table within <div id="ScrollHeader">, insert THEAD before the first TR, change the TD to TH in the first line and close it with </thead>.
I have tried using $("div p[id^='ScrollHeader']").length to find the DIV and $("tr:first") to perform <table>.prepend(document.createElement('thead')); without success.
Try this:
$('#ScrollHeader table tr:eq(0)').wrap('<thead />');
$('#ScrollHeader table tr:eq(0) td').each(function () {
$('#ScrollHeader table tr:eq(0)').append($('<th />').html($(this).html()));
$(this).remove();
});
$('#ScrollHeader tr:first')
.wrap('<thead />')
.children().each(function(){
text = $(this).text();
$(this).replaceWith('<th>'+text+'</th>');
});
$('#ScrollHeader thead').insertBefore('#ScrollHeader tbody');
you can see it working here

Categories

Resources