Merging duplicated rows in JSP table - javascript

I'm trying to generate a HTML table from an input Excel sheet using Apache POI in a JSP page. I have managed to code the part where the data is fetched from Excel and displayed as a HTML table, but the problem is some of the primary IDs has been duplicated in severals rows but they have different values in other rows. Example (2 Johns with Different Lastname):
<table>
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr>
<td>John</td>
<td>Jackson</td>
<td>94</td>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
<td>80</td>
</tr>
</table>
The code to generate the table :
out.println("<table>");
while (rowIter.hasNext())
{
row =(HSSFRow)rowIter.next();
input_fname = row.getCell(0);
input_lname = row.getCell(1);
input_age = row.getCell(2);
fname = input_fname.getRichStringCellValue().getString();
lname = input_lname.getRichStringCellValue().getString();
age = input_age.getRichStringCellValue().getString();
out.println("<tr>");
out.println("<td>"+fname+"</td>");
out.println("<td>"+lname+"</td>");
out.println("<td>"+age+"</td>");
out.println("</tr>");
}
}
out.println("</table>");
Please anyone advise me how can I merge the duplicated rows according to the Primary ID, First Name as below :
<table>
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr>
<td rowspan="2">John</td>
<td>Jackson</td>
<td>94</td>
</tr>
<tr>
<td>Doe</td>
<td>80</td>
</tr>
</table>
I have tried searching for similar question but i couldn't find any solution for my problem and I'm quite a beginner in Javascript and JQuery (maybe that's the problem). Any suggestions is much appreciated. Thanks in advance!

You are asking the wrong question. Wouldn't it be much easier to write the HTML correctly in the first place rather than try to do some merge on the HTML?
Thus, loop over the entries and put them in some suitable datastructure e.g. a Map keyed by fname and with a list as the value. Person class is a simple bean to hold the data.
Map<String, List<Person>> people = new TreeMap<String, List<Person>> ();
while (rowIter.hasNext())
{
row =(HSSFRow)rowIter.next();
input_fname = row.getCell(0);
input_lname = row.getCell(1);
input_age = row.getCell(2);
fname = input_fname.getRichStringCellValue().getString();
lname = input_lname.getRichStringCellValue().getString();
age = input_age.getRichStringCellValue().getString();
Person person = new Person(fname, lname, age);
if(! people.containsKey(person.fname)){
people.put(person.fname, new ArrayList<Person>());
}
people.get(person.fname).add(person);
}
}
Then loop over this data structure and write the HTML:
for(String key : people.keySet()){
List<Person> persons = people.get(key));
int rowSpan = persons.size();
//write the HTML accordingly.
}

You can:
add a class when printing the name in your back-end code e.g. out.println("<td class="fname">"+fname+"</td>");
and then with jQuery
var last_selected_name = "";
/* Get all the first names cells */
jQuery('td.fname').each(function(i,obj){
current_name = jQuery(obj).text();
/* check for repeated names */
if (current_name == last_selected_name)
{
jQuery("td.fname:contains('"+current_name+"')").each(function(index,object){
if (index == 0)
{
/* check if already has rowspan attribtue */
row_span = jQuery(object).attr('rowspan')?jQuery(object).attr('rowspan'):1;
/* add one */
row_span++;
/* include the new rowspan number */
jQuery(object).attr('rowspan',row_span)
}
else
{
/* delete the other first name cells */
jQuery(object).remove();
}
})
}
last_selected_name = current_name;
})

Related

How to sort a tree table by rows (header on the left) with no <thead> [duplicate]

This question already has answers here:
HTML table sortable by ROW instead of COLUMN with JavaScript?
(2 answers)
Closed 1 year ago.
I want to sort a tree table not by columns but rows, its header is on the left in the tree part.
My tree table looks like this
the tree table plugin I used.
And the code is something like this
<table>
<tr data-node-id="index">
<th>Index</th>
<td>...</td>
<td>...</td>
</tr>
<tr data-node-id="patient">
<th>Patient Characteristics</th>
</tr>
<tr data-node-id="name" data-node-pid="patient">
<th>Name</th>
<td>...</td>
<td>...</td>
</tr>
<tr data-node-id="DOB" data-node-pid="patient">
<th>DOB</th>
<td>...</td>
<td>...</td>
</tr>
<tr data-node-id="age" data-node-pid="patient">
...
There is no <thead> part, so many sorting methods not work well on this table. I'm new to javascript sort of things, and have no idea if this is easy to do. But I did not find methods for this situation online, so I try to ask for help.
First, access the table element:
var table = document.getElementById("table").children[0]; // You can just add an id to the table
Here is a function for sorting by row:
function sortRow(rowNum) { // rowNum is index of row: for example, name is 2
var answerArray = [];
for (i = 1; i < table.children[rowNum].children.length; i++) {
answerArray.push(table.children[rowNum].children[i].innerHTML);
}
return answerArray;
This function takes in the row number, and returns an array of all values in the row.

Parsing html with cheerio

I used cheerio for the first time today
This is a simplified version of the html source I want.
<div id="country-table">
<!-- div duplicate cause style -->
<div>
<div>
<table>
<tbody>
<tr>
<td>1</td>
<td>USA</td>
<td>1.6</td>
<td>75.8</td>
<td>132,000</td>
</tr>
<tr>
<td>2</td>
<td>INDIA</td>
<td>12123</td>
<td>1322</td>
<td>123213</td>
</tr>
<tr>
<td>3</td>
<td>BRAZIL</td>
<td>3123</td>
<td>213123</td>
<td>134</td>
</tr>
<tr>
<!-- and more... -->
</tbody>
</table>
</div>
</div>
</div>
and i tried to this:
const axios = require("axios").default;
const cheerio = require("cheerio").default;
axios.get("https://coronaboard.kr").then((html) => {
const arr = [];
const $ = cheerio.load(html.data, { xml: true, xmlMode: true });
const data = $("#country-table>div>div>table>tbody").each((index, item) => {
arr.push(item);
});
console.log(arr);
});
I want to put information in td into tr.
ex){number:x,name:USA,confirmed:x,and more...}
If anyone knows how to do it, please answer me!
If you're wanting to extract the data from the table, then this will help. Follow the comments to help you understand how it works.
var $ = cheerio.load(html.data);
// targets the specific table with a selector
var html_table = $('#country-table>div>div>table');
// gets table cell values; loops through all tr rows
var table_data = html_table.find('tr').map(function() {
// gets the cells value for the row; loops through each cell and returns an array of values
var cells = $(this).find('td').map(function() {return $(this).text().trim();}).toArray();
// returns an array of the cell data collected
return [cells];
}).toArray();
// output table data
console.log('table_data', table_data);

Pass values from a row to another JSP using jquery

I'm trying to get row values from a bootstrap table to send them to another JSP document while using jQuery, however seems like I can't find a proper way to do that.
<table class="table table-hover">
<thead>
<%
int serial = 0;
int id = 0;
String name = null;
double ammount = 0;
String date = null;
User user = null;
%>
<tr>
<th><%="Serial"%></th>
<th><%="Cost ID"%></th>
<th><%="Cost Name"%></th>
<th><%="Cost Ammount"%></th>
<th><%="Cost Date"%></th>
</tr>
</thead>
<tbody>
<%
try {
int id_id = (int) session.getAttribute("id");
List<Object[]> costs = scm.viewAll(sum.getUser(id_id));
for (Object[] cost : costs) {
id = (int) cost[0];
name = (String) cost[1];
ammount = (double) cost[2];
date = (String) cost[3];
serial += 1;
%>
<tr class="clickable-row" data-href="updatesingle">
<td><%=serial%></td>
<td><%=id%></td>
<td><%=name%></td>
<td><%=ammount%></td>
<td><%=date%></td>
</tr>
<%
}
} catch (Exception e) {
response.sendRedirect("home");
}
%>
This code above is the table code. As you can see the rows are clickable and I'm redirecting to a new page(JSP) when a row clicked, using jQuery:
jQuery(document).ready(function($) {
$(".clickable-row").click(function() {
window.document.location = $(this).data("href");
});
});
What I'm trying to do, is to pass for example the Cost ID(id variable) value to the next JSP page and manipulate it in some way, and the value should be of the specific row I clicked on. Is there a way to do so?
P.S I'm new to jQuery so please be gentle :)
You can save the id in a data- attribute:
<tr class="clickable-row" data-href="updatesingle" data-id="<%=id%>">
And, if you're going to use that ID with JSP, then you can pass it as a parameter to the other page:
window.document.location = $(this).data("href") + "?id=" + $(this).data("id");
But if you're going to get it with jQuery in the other page, you can save the ID into the sessionStorage:
sessionStorage.setItem('clickedUserID', $(this).data("id"));
window.document.location = $(this).data("href");
In the other page, you just get it from the sessionStorage and use it:
var userID = sessionStorage.getItem('clickedUserID');
// do something with the ID
Pro-tip: if you are only printing out a String into your JSP, you can simply just type it into the HTML (and save yourself the extra coding)
Here's my attempt to answer your question:
$(document).ready(function($) {
$(".clickable-row").click(function() {
// you can add the URL for the new page here like:
// var newLocation = "<URL for JSP>?paramName=" + paramValue
// this is just an example of how it would work
var newLocation = window.document.location + "?href=" + $(this).data("href");
alert( newLocation );
// oher values
console.log( $(this).find("td").eq(1).html() ); // 1 for id column, 2 for name, 3 for amount, etc.
window.document.location = newLocation;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<table class="table table-hover">
<tr>
<th>Serial</th>
<th>Cost ID</th>
<th>Cost Name</th>
<th>Cost Amount</th>
<th>Cost Date</th>
</tr>
<tr class="clickable-row" data-href="updatesingle1">
<td>1</td>
<td>id1</td>
<td>name1</td>
<td>amount1</td>
<td>date1</td>
</tr>
<tr class="clickable-row" data-href="updatesingle2">
<td>2</td>
<td>id2</td>
<td>name2</td>
<td>amount2</td>
<td>date2</td>
</tr>
<tr class="clickable-row" data-href="updatesingle3">
<td>3</td>
<td>id3</td>
<td>name3</td>
<td>amount3</td>
<td>date3</td>
</tr>
</table>

Convert table HTML to JSON

I have this:
<table>
<tr>
<th>Name:</th>
<td>Carlos</td>
</tr>
<tr>
<th>Age:</th>
<td>22</td>
</tr>
</table>
And I need a JSON format.
{"Name":"Carlos","Age": 22}
I've tried with https://github.com/lightswitch05/table-to-json but it doesn't work for the headings in every row :(
EDIT: http://jsfiddle.net/Crw2C/773/
You can convert the table in the OP to the required format by first converting it to an Object, then using JSON.stringify to get the required string:
<table id="t0">
<tr>
<th>Name:</th>
<td>Carlos</td>
</tr>
<tr>
<th>Age:</th>
<td>22</td>
</tr>
</table>
<script>
function tableToJSON(table) {
var obj = {};
var row, rows = table.rows;
for (var i=0, iLen=rows.length; i<iLen; i++) {
row = rows[i];
obj[row.cells[0].textContent] = row.cells[1].textContent
}
return JSON.stringify(obj);
}
console.log(tableToJSON(document.getElementById('t0'))); // {"Name:":"Carlos","Age:":"22"}"
</script>
However, that is an ad hoc solution, so will need some work to be adapted to a more general case. It shows the concept though.
Note that there is no guarantee that the object properties will be returned in the same order as they appear in the table, you may get {"Age:":"22","Name:":"Carlos"}.
Assuming all you need is to get the first/second cells of each row as key/value pairs, you can use .reduce() to iterate of the rows and just grab the text content of .cells[0] and .cells[1] to use as each key/value pair:
var t = document.querySelector("table");
var j = [].reduce.call(t.rows, function(res, row) {
res[row.cells[0].textContent.slice(0,-1)] = row.cells[1].textContent;
return res
}, {});
document.querySelector("pre").textContent = JSON.stringify(j, null, 2);
<table>
<tr>
<th>Name:</th>
<td>Carlos</td>
</tr>
<tr>
<th>Age:</th>
<td>22</td>
</tr>
</table>
<pre></pre>
The Array.prototype.reduce method takes a collection and uses an accumulator to reduce it down to whatever state you want. Here we just reduce it to an object, so we pass one in after the callback.
For every row, we use the first cell's content as the object key, and the second cell's content as the value. We then return the object from the callback so that it's given back to us in the next iteration.
Finally, .reduce() returns the last thing we returned (which of course is the object we started with), and that's your result.
var t = document.querySelector("table");
var j = [].reduce.call(t.rows, function(res, row) {
res[row.cells[0].textContent.slice(0,-1)] = row.cells[1].textContent;
return res
}, {});
document.querySelector("pre").textContent = JSON.stringify(j);
<table>
<tr>
<th>Name:</th>
<td>Carlos</td>
</tr>
<tr>
<th>Age:</th>
<td>22</td>
</tr>
</table>
<pre></pre>
The Table-to-JSON library that you are using is expecting a different format in your table.
It is expecting a table with all of your headers in the first row, followed by the data in subsequent rows.
In other words, it's expecting your table to be structured like this
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr>
<td>Carlos</td>
<td>22</td>
</tr>
</table>
Here's a forked version of your JSFiddle in which this is working.

How do I affect/select all descendants with Treetable plugin using jQuery / javascript

A piece of my HTML code looks like this:
<tr data-tt-id="1">
<td>Parent</td>
</tr>
<tr data-tt-id="2" data-tt-parent-id="1">
<td>Child 1</td>
</tr>
<tr data-tt-id="4" data-tt-parent-id="2">
<td>Child 1's child</td>
</tr>
<tr data-tt-id="3" data-tt-parent-id="1">
<td>Child 2</td>
</tr>
<tr data-tt-id="5" data-tt-parent-id="3">
<td>Child 2's child</td>
</tr>
I'm selecting the parent which has data-tt-id="1" by using this:
$('tr[data-tt-parent-id="1"]');
But I want all of the children and children's children too, no matter how deep the tree might be.
As you can see data-tt-id is the child's unique ID and data-tt-parent-id is the ID which the child is appended to.
I was thinking about looping through each one of them, but I have no idea how I would achieve that.
How do I select all descendants for the tr that has data-tt-id set to "1"?
function getDescendants(el, curset) {
curset = curset || $(""); // default to empty set
var id = el.data('tt-id');
var children = $("tr[data-tt-parent-id="+id+"]");
if (children.length) {
curset = curset.add(children);
children.each(function() {
curset = curset.add(getDescendants($(this), curset));
});
}
return curset;
}
There's probably more idiomatic ways to write this without having to reassign curset = ... in several places, but this works.
DEMO

Categories

Resources