Grouping HTML table rows with rowspan - javascript

I am struggling with this issue for a while and really appreciate if someone can give some idea on how I can move forward with.
The idea is to reduce the number of rows in the table by grouping the relevant data in the below format.
I need to convert the JSON response coming from server (non-grouped data) to a particular format so that I can paint the table with the grouped data.
**Initial Layout**
+------------+-----------+--------+------------+
| Category | Product | Size | Shipping
+------------+-----------+--------+------------+
| Category 1 | Product 1 | Big | Free |
| Category 1 | Product 2 | Small | Free |
| Category 1 | Product 3 | Big | Free |
| Category 1 | Product 4 | Small | Free |
+------------+-----------+--------+-------------
**Expected Result**
+------------+----------------------+--------+-----------
| Category | Product | Size | Shipping
+------------+----------------------+--------+------------
| Category 1 | Product 1, Product 3 | Big | Free |
| | Product 2, Product 4 | Small | Free |
+------------+----------------------+--------+----------
More details in the jsfiddle:
https://jsfiddle.net/zy8kj2tb/2/
// please see the code in jsfiddle

<h3>
Initial layout:
</h3>
<h6>
<p>
Category = Category 1, Category 2, etc or "blank"
</p>
<p>
Product = Product 1, Product 2, etc or "blank"
</p>
<p>
Size = Big, Small, XL, etc or "blank"
</p>
<p>
Shipping = Free, Standard, Expedited, etc or "blank"
</p>
<p>
dont group blank rows with cat, prod, size = make it as individual row
</p>
</h6>
<div id="initialLayout">
</div>
<h3>Expected result:</h3>
<table id="expectedTable" border="1" cellpadding="3" cellspacing="0">
<tr>
<th>Category</th>
<th>Product</th>
<th>Size</th>
<th>Shipping</th>
</tr>
<tr>
<td rowspan=2>Category 1</td>
<td rowspan="2">Product 1, Product 3 <br>Product 2, Product 4</td>
<td rowspan="2">Big <br>Small</td>
<td rowspan="2">Free</td>
</tr>
</table>
<br/>
Just replace your HTML with this one, I did two things -
Changed first row with -
<td rowspan="2">Product 1, Product 3 <br>Product 2, Product 4</td>
<td rowspan="2">Big <br>Small
</td>
Removed respective td tags from the second row

I just looked at your code
where you have written
<td rowspan=2>Category 1</td>
<td>Product 1, Product 3</td>
<td>Big</td>
<td rowspan=2>Free</td>
It should be
<td rowspan="2">Category 1</td>
<td>Product 1, Product 3</td>
<td>Big</td>
<td rowspan="2">Free</td>
you have just missed some quotes

Related

Using *ngFor to display string values from array

I have an array which is created from splitting a string using str.split() and this creates an array and it looks like this:
var array = [
"TEXT1,1234,4321,9876",
"TEXT2,2345,5432",
"TEXT3,6543,3456"
]
I want to be able to display this information in a table using *ngFor.
I have tried this (from this question):
<tr>
<td *ngFor="let info of array">{{info.join(",")}}</td>
</tr>
But I get this error:
ERROR TypeError: _v.context.$implicit.join is not a function
at Object.eval [as updateRenderer]
The table should look like this:
TITLE | VALUE1 | VALUE2 | VALUE3
--------------------------------
TEXT1 | 1234 | 4321 | 9876
--------------------------------
TEXT2 | 2345 | 5432 |
--------------------------------
TEXT3 | 6543 | 3456 |
How do I achieve this table?
To make array from string with , delimiters use String.prototype.split method
<tr *ngFor="let row of array">
<td *ngFor="let info of row.split(',')">{{info}}</td>
</tr>
Ng-run Example
You will need two *ngFors. One to loop through each item in the array and one to iterate through each item in the array that you'll create by splitting the string with ,
Give this a try:
<table border="1">
<thead>
<tr>
<td>TITLE</td>
<td>VALUE 1</td>
<td>VALUE 2</td>
<td>VALUE 3</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of array">
<td *ngFor="let column of row.split(',')">
{{ column }}
</td>
</tr>
</tbody>
</table>
Here's a Working Sample StackBlitz for your ref.

AngularJs - Reference the same scope property from multiple ngRepeat's

I have multiple ngRepeats generate table contents, depending on the view the user wants to see, a different ngRepeat is used to generate the table. When the user switches their view, and one of the following is removed from the DOM and another added, the new ngRepeat does not reference to the same pagination.filteredData array.
Example: Main is my controller, using controller as syntax.
<tr ng-if="Main.tableConfig.programGranularity == 'overall'" ng-repeat="item in Main.pagination.filteredData = ( Main.data.overallData | filterByDateRange | filter: Main.tableConfig.generalSearch | orderBy: ['Date', 'Name']) | startFrom: Main.pagination.startAtIndex | limitTo: Main.pagination.pageSize">
<td ng-repeat="column in Main.tableConfig.columnsConfig | selectColumnsByGranularity: Main.tableConfig.programGranularity">
<span ng-if="!column.isDate" ng-bind="item[column.dataValue] | ifEmpty: 0"></span>
<span ng-if="column.isDate" ng-bind="item[column.dataValue] | date:'MM/dd/yyyy': 'UTC' | ifEmpty: 0"></span>
</td>
</tr>
<tr ng-if="Main.tableConfig.programGranularity == 'team'" ng-repeat="item in Main.pagination.filteredData = ( Main.data.teamData | filterByDateRange | filter: Main.tableConfig.generalSearch | orderBy: ['Date', 'Name']) | startFrom: Main.pagination.startAtIndex | limitTo: Main.pagination.pageSize">
<td ng-repeat="column in Main.tableConfig.columnsConfig | selectColumnsByGranularity: Main.tableConfig.programGranularity">
<span ng-if="!column.isDate" ng-bind="item[column.dataValue] | ifEmpty: 0"></span>
<span ng-if="column.isDate" ng-bind="item[column.dataValue] | date:'MM/dd/yyyy': 'UTC' | ifEmpty: 0"></span>
</td>
</tr>
<tr ng-if="Main.tableConfig.programGranularity == 'colleague'" ng-repeat="item in Main.pagination.filteredData = ( Main.data.parsedData | filterByDateRange | filter: Main.tableConfig.generalSearch | orderBy: ['Date', 'Name']) | startFrom: Main.pagination.startAtIndex | limitTo: Main.pagination.pageSize">
<td ng-repeat="column in Main.tableConfig.columnsConfig | selectColumnsByGranularity: Main.tableConfig.programGranularity">
<span ng-if="!column.isDate" ng-bind="item[column.dataValue] | ifEmpty: 0"></span>
<span ng-if="column.isDate" ng-bind="item[column.dataValue] | date:'MM/dd/yyyy': 'UTC' | ifEmpty: 0"></span>
</td>
</tr>
I want the same pagination.filteredData array to be set by each of the ngRepeat directives. However, only the first ngRepeat that runs sets the value and no other ngRepeat will set it again.
I've tried ngInit and initializing an object with pagination inside of it, and referencing that in my ngRepeat. I have also tried using $parent.pagination.filteredData.
Using AngularJS v1.5.0
How do I get this to work?
Similar to https://stackoverflow.com/questions/38235907/angularjs-service-variable-not-being-set-inside-of-ngrepeat but reworded and fundamentally different. Solving the same problem though.
Edit: Refactored to utilize the controller as syntax, the problem still persists. To me it seems that when I switch to a different ngRepeat, a new array and reference is created, instead of overwriting the current arrays values.
Okay, I have spent some time putting together a demo replicating (as best I could) the code that you have provided <-- Broken, and I think I understand your issue. You say "the first ng-repeat that runs sets the value", and I think it's actually the LAST ng-repeat that runs that is setting it. It's not having a problem setting the value, the problem is that all 3 ng-repeats run every time, so it's always the last one that wins.
The reason this happens is because ng-repeat executes BEFORE ng-if for the common case of <element ng-if="item.showMe" ng-repeat="item in Main.items"></element>
That being said, even though your ng-if condition is false, so the <tr> does not get displayed, the ng-repeat has already run, and already set Main.pagination.filteredData
I think your best course of action would be to move your ng-if up one level to the <tbody>. It would look like the following:
WORKING DEMO <-- Working
<table>
<thead>
<tr>
<th>Name</th>
<th>Data</th>
<th>Date</th>
</tr>
</thead>
<tbody ng-if="Main.tableConfig.programGranularity == 'overall'" >
<tr ng-repeat="item in Main.pagination.filteredData = (Main.data.overallData | filterByDateRange | orderBy: ['date', 'name']) | startFrom: Main.pagination.startAtIndex | limitTo: Main.pagination.pageSize">
<td ng-bind="item.name"></td>
<td ng-bind="item.overall"></td>
<td ng-bind="item.date"></td>
</tr>
</tbody>
<tbody ng-if="Main.tableConfig.programGranularity == 'team'" >
<tr ng-repeat="item in Main.pagination.filteredData = (Main.data.teamData | filterByDateRange | orderBy: ['date', 'name']) | startFrom: Main.pagination.startAtIndex | limitTo: Main.pagination.pageSize">
<td ng-bind="item.name"></td>
<td ng-bind="item.team"></td>
<td ng-bind="item.date"></td>
</tr>
</tbody>
</table>

How to add the count values of similar event id using javascript?

I have a table in which there are three columns i.e. Event id, Event and Counts. There can be multiple rows with same event id having their own counts values under Counts column. I have to find out the distinct Event id and then add up their corresponding count values and display the output table with distinct Event id, Event and Count in which the count value will be total sum of available counts. I tried to show tabular form of what I want to do as following:
+--------+--------------+----------+
| Ashley Janes |
+--------+--------------+----------+
|Eventid | Event | Count |
+--------+--------------+----------+
| 5 | Wash apple | 10 |
| 2 | cook potatoes| 20 |
| 8 | cut chillies | 5 |
+--------+--------------+----------+
| Taylor Perry |
+--------+---------------+---------+
| 2 | cook potatoes | 30 |
| 5 | Wash apple | 40 |
| 8 | cut chillies | 60 |
Now I have to add count values of corresponding event id and display it in a result table as following::
+--------+--------------+----------+
|Eventid | Event | Count |
+--------+--------------+----------+
| 5 | Wash apple | 50 |
| 2 | cook potatoes| 50 |
| 8 | cut chillies | 65 |
+--------+--------------+----------+
so far I have done following:
Response.Write "<div><table><tr>"
Response.Write"<td class='tdcell1'>Event ID</td><td class='tdcell1'>Count</td></tr>"
Response.Write"<tr><td align=center width= '15%'></td><td><div class= 'resultSum'></div></td></tr>"
Response.Write"</table><div>"
<script>
$(function() {
GetEventIds('#displaytable')
});
function GetEventIds(tableIdWithHash) {
var eventIds = [];
var eventSum = Number(0);
var count = Number(0);
$(tableIdWithHash).find('.Idevent').each(function(i){
var eId = $(this).html();
if (eventIds.indexOf(eId) === -1)
eventIds.push($(this).html());
if (eId = eventIds)
count++;
eventSum += Number($(this).html());
$(".resultSum").html(eventSum);
});
alert('EventIds: ' + JSON.stringify(eventIds));
return eventIds;
}
</script>
Code for the table need to be parsed.
<table id= 'displaytable' width='35%' border=1 style= 'margin-bottom:35px; margin-top:35px;'>
<tr>
<td class='tdcell1'>Event ID</td>
<td class='tdcell1'>Event</td>
<td class='tdcell1'>Count</td>
</tr>
<tr style='font-size:13px;'>
<td align='right' class='tdcell1' colspan='3'>Ashley Janes</td>
</tr>
<tr style='font-size:13px;'>
<td align=center class='Idevent' width= '15%'> 5 </td>
<td align=center class='eventNames' width= '35%'> Wash Apple </td>
<td class='eventCounts' align=center width= '15%'>11</td>
</tr>
<tr style='font-size:13px;'>
<td align=center class='Idevent' width= '15%'> 2 </td>
<td align=center class='eventNames' width= '35%'> Cook Potatoes </td>
<td class='eventCounts' align=center width= '15%'>20</td>
</tr>
<tr style='font-size:13px;'>
<td align='right' class='tdcell1' colspan='3'>Taylor Perry</td>
</tr>
<tr style='font-size:13px;'>
<td align=center class='Idevent' width= '15%'> 2 </td>
<td align=center class='eventNames' width= '35%'> Cook Potatoes </td>
<td class='eventCounts' align=center width= '15%'>20</td>
</tr>
<tr style='font-size:13px;'>
<td align=center class='Idevent' width= '15%'> 5 </td>
<td align=center class='eventNames' width= '35%'> Wash Apple </td>
<td class='eventCounts' align=center width= '15%'>106</td>
</tr>
</table>
My code gives me the output for the sum of the event id not the counts. How do I do it using JavaScript? Please help.
Take a look at this code and wether works as you expect it.
$(function() {
GetEventIds('#displaytable')
});
//this is a bad function, because it does way more than it says.
function GetEventIds(tableIdWithHash) {
//a little helper
//convert a value to int32. any non-numeric value -> 0
//only the low 32-bits are kept, if the value exceeds the range
//and removes all bits after the dot (2.9 -> 2 and -2.9 -> -2)
function int(v){ return v|0; }
var eventSum = 0;
var events = {};
$(tableIdWithHash).find('.Idevent').each(function(i){
var $this = $(this);
var eId = $this.text().trim();
//finding the .eventCount-node of this row
var count = int( $this.siblings('.eventCounts').text().trim() );
events[eId] = int( events[eId] ) + count;
//still don't get what #resultSum should contain (logically)
//the total amount of events, independent of the event-id?
eventSum += count;
});
$("#resultSum").html(eventSum);
var eventIds = Object.keys(events);
console.log('EventIds: ', eventIds);
console.log('Event counts by Id: ', JSON.stringify(events));
return eventIds;
}
Still need some info on the purpose/meaning of #resultSum. I made just an assumption on that; am i right?
And as I commented on the function, What is the purpose of this function? It does more than it says. This may lead to confusion/bugs. Maybe you want to split this into multiple functions, or rename it and drop the return-value.
Or maybe you want to parse the table into some data-structure and operate on this? But then again it may be wiser to paste JSON out of the backend, than parsing some markup.

How to display a multi dimensional array as a table?

This problem's been haunting me for days... I have the following JSON that I'm trying to render as a table using Tempo.js but keep getting nothing rendered:
[
{
"id":"xxxxxxxxxxxxxxxxxxxxxxxxxx",
"name":"Family One",
"parents":[
{
"id":"yyyyyyyyyyyyyyyyyyyyyyyyyy",
"name":"John Doe",
"children":[
{
"id":"zzzzzzzzzzzzzzzzzzzzzzzzz",
"name":"Fabrice A",
"description":"Good kid",
"Age":"20",
"Weight":"60"
}
]
},
{
"id":"hhhhhhhhhhhhhhhhhhhhhhhhhh",
"name":"Jane Doe",
"children":[
{
"id":"wwwwwwwwwwwwwwwwwwwwwwww",
"name":"Maurice A",
"description":"Bad kid",
"Age":"22",
"Weight":"50"
}
]
}
]
},
{
"id":"xxxxxxxxxxxxxxxxxxxxxxxxxx2",
"name":"Family Two",
"parents":[
{
"id":"yyyyyyyyyyyyyyyyyyyyyyyyyy2",
"name":"Sonny Doe",
"children":[
{
"id":"zzzzzzzzzzzzzzzzzzzzzzzzz2",
"name":"Juan B",
"description":"Good kid",
"Age":"30",
"Weight":"70"
},
{
"id":"zzzzzzzzzzzzzzzzzzzzzzzzz3",
"name":"Alberto B",
"description":"Fine kid",
"Age":"20",
"Weight":"60"
},
{
"id":"zzzzzzzzzzzzzzzzzzzzzzzzz4",
"name":"Roberto B",
"description":"Medium kid",
"Age":"10",
"Weight":"50"
}
]
}
]
}
]
The table is supposed to look like this:
_______________________________________________________________________________________
| FAMILY NAME | PARENTS | CHILD NAME | CHILD DESCRIPTION | CHILD AGE | CHILD WEIGHT |
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
| Family One | John Doe | Fabrice A | Good kid | 20 | 60 |
| |''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
| | Jane Doe | Maurice A | Bad kid | 22 | 50 |
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
| Family Two | Sonny Doe | Juan B | Good kid | 30 | 70 |
| | | Alberto B | Fine kid | 20 | 60 |
| | | Roberto B | Medium kid | 10 | 50 |
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Please notice how the family cell stretches to house more than one parent rows, and the parent cell streches to house more than one children rows.
I prepare the JSON in js in a variable called familyTree, and then call Tempo.prepare('family-list').render(familyTree);
No I've read all of the documentation for tempo.js (which wasn't too long), but I still haven't found a way of rendering the table properly. Here's what I got so far:
<div id="family-list">
<table id="families">
<tr data-before-template='data-before-template'>
<th>
FAMILY NAME
</th>
<th>
PARENTS
</th>
<th>
CHILD NAME
</th>
<th>
CHILD DESCRIPTION
</th>
<th>
CHILD AGE
</th>
<th>
CHILD WEIGHT
</th>
</tr>
<tr data-template='data-template'>
<td id="family-column">
{{name}}
</td>
<td id="parent-column" data-template-for='parents'>
{{name}}
</td>
<td colspan="4">
<table id='children-table' data-template-for="children">
<tr>
<td>
{{name}}
</td>
<td>
{{description}}
</td>
<td>
{{age}}
</td>
<td>
{{weight}}
</td>
</tr>
</table>
</td>
</tr>
I've used tempo before. I've even mixed it with wkhtmltopdf to render some nice-looking pdf files. But I just cannot solve this. If any of you out there has been through anything similar..would you please share your experience? Thanks so much in advance.
Using tempo.js is not ideal to render hierarchical data in a table. To render hierarchical data, tempo.js requires that the HTML elements also exists in a hierarchy. This is not ideal when dealing with tables, because creatign a table inside a table cell will eventually lead to column alignment issues. You can take care of alignment issues to a certain degree by fixing the width of each column, but this will not be a perfect solution.
Having said above, I've fixed your HTML markup to render your JSON data using tempo.js. See the changes below (jsfiddle here):
<div id="family-list">
<table id="families">
<tr data-before-template='data-before-template'>
<th width="100px">
FAMILY NAME
</th>
<th width="100px">
PARENTS
</th>
<th width="100px">
CHILD NAME
</th>
<th width="150px">
CHILD DESCRIPTION
</th>
<th width="50px">
CHILD AGE
</th>
<th width="50px">
CHILD WEIGHT
</th>
</tr>
<tr data-template='data-template'>
<td id="family-column">
{{name}}
</td>
<td colspan="5">
<table cellpadding="0">
<tr data-template-for='parents'>
<td width="100px">
{{name}}
</td>
<td>
<table id='children-table' cellpadding="0">
<tr data-template-for="children">
<td width="100px">
{{name}}
</td>
<td width="150px">
{{description}}
</td>
<td width="50px">
{{Age}}
</td>
<td width="50px">
{{Weight}}
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>

Insert multiple rows in a cell in HTML Table

I am trying to insert rows within a cell in HTML Table using jquery, I want something like this:
--------------
ID | Sec | Div
--------------
1 | S1 | D1
| S2 | D2
| S3 | D3
--------------
2 | S3 | D3
| S4 | D4
| S5 | D5
--------------
Here is what I have so far:
function insertRows(this){
var Rows1 = '<tr><td> S1 </td></tr><tr><td> S2 </td></tr><tr><td> S3 </td></tr>'
var Rows2 = '<tr><td> S3 </td></tr><tr><td> S4 </td></tr><tr><td> S5 </td></tr>'
this.srcElement.parentElement.nextSibling.outerHTML = Rows1
this.srcElement.parentElement.nextSibling.nextSibling.outerHTML = Rows2
}
What is does is, it inserts all in the same Row, something like this:
---------------------
ID | Sec | Div
---------------------
1 | S1S2S3 | D1D2D3
---------------------
2 | S3S4S5 | D3D4D5
---------------------
How can I make this to work?
You Can Fullfill your requirement without using jquery
just Paste this Code inside body tag
<table>
<tr>
<td >ID</td>
<td>SEC</td>
<td>DIV</td>
</tr>
<tr>
<td rowspan="3">1</td>
<td>S1</td>
<td>D1</td>
</tr>
<tr>
<td>S2</td>
<td>D2</td>
</tr>
<tr>
<td>S3</td>
<td>D3</td>
</tr>
<tr><td colspan="3">---------------------</td></tr>
<tr>
<td>ID</td>
<td>SEC</td>
<td>DIV</td>
</tr>
<tr>
<td rowspan="3">2</td>
<td>S1</td>
<td>D1</td>
</tr>
<tr>
<td>S2</td>
<td>D2</td>
</tr>
<tr>
<td>S3</td>
<td>D3</td>
</tr>
</table>
here you can find live example http://jsfiddle.net/Anujyadav123/AdQy3/
.innerHTML is rather broken when dealing with tables, at least under IE.
Your choices are:
Restrict the use of .innerHTML to only change the contents of a td element.
Use .innerHTML to replace the ENTIRE table structure
Use DOM methods to manipulate table rows and table cells.
https://developer.mozilla.org/en-US/docs/Traversing_an_HTML_table_with_JavaScript_and_DOM_Interfaces
take a look here Add colspan and rowspan on table on the fly
OR
is it important to add row, if not you are able to add your values into cell
Example:
function showP(){
txt1 = $($('#myTable').find('TR').find('TD')[1]).html()+'</br>S1'
txt3 = $($('#myTable').find('TR').find('TD')[3]).html()+'</br>D1'
$($('#myTable').find('TR').find('TD')[1]).html(txt1 )
$($('#myTable').find('TR').find('TD')[3]).html(txt3 )
}

Categories