Sort/Group an Array by 2 different Attributes - javascript

I have a grouped/sorted array based on its "Program" attribute which is great. But now I need to sort by a different attribute (Deliverable) inside of that grouping, is that possible? And if so how can I accomplish that?
Here is a picture of my table.
See how it is organized by Program? Inside of the Program grouping, I want to also sort/group based on the Deliverable item, since there will be way more than two within each Program. Also, if it isn't too much work I would also love to make those rows clickable (expand/collapse) so the table isn't 100 rows long once it is loaded.
Here is my expected output:
Expected Result
+------------+----------------------+-----------+------------+--------------+---------------------+
| Program | Deliverable | Date | Approved | Notes | To |
+------------+----------------------+-----------+------------+--------------+---------------------+
| Program 1 | |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | Monthly Status Report| |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | | 05/10/2020| Yes | Example Notes| example#example.com |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | | 03/30/2020| No | Example Notes| example#example.com |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | Meeting Minutes | |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | | 02/10/2010| Yes | Example Notes| example#example.com |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | | 03/30/2020| Yes | Example Notes| example#example.com |
+------------+----------------------+-----------+------------+--------------+---------------------+
| Program 2 | |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | Monthly Status Report| |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | | 05/10/2020| Yes | Example Notes| example#example.com |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | | 03/30/2020| No | Example Notes| example#example.com |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | Meeting Minutes | |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | | 02/10/2010| Yes | Example Notes| example#example.com |
+------------+----------------------+-----------+------------+--------------+---------------------+
| | | 03/30/2020| Yes | Example Notes| example#example.com |
+------------+----------------------+-----------+------------+--------------+---------------------+
Here is my code:
.then(([r1, r2, r3]) => {
const objItems = r1.concat(r2,r3);
console.log(JSON.stringify(objItems));
console.log(objItems);
var tableContent =
'<table id="deliverablesTable" style="width:100%" border="1 px"><thead><tr colspan = "5"><td><strong>Program</strong></td>' +
"<td><strong>To</strong></td>" +
"<td><strong>Date Submitted</strong></td>" +
"<td><strong>Approved</strong></td>" +
"<td><strong>Notes</strong></td>" +
"<td><strong>Deliverable</strong></td>" +
"</tr></thead><tbody>";
var sortedObj = {}
objItems.forEach(item => {
var program = item.Program;
delete(item.Program); //remove this line to keep the program in the item data
if (!sortedObj[program]) {
sortedObj[program] = [];
}
sortedObj[program].push(item);
});
Object.keys(sortedObj).forEach(key => {
tableContent += "<tr>";
tableContent += "<td>" + key + "</td>";
tableContent += "</tr>";
sortedObj[key].forEach(obj => {
tableContent += "<tr>";
tableContent += "<td> </td>";
tableContent += "<td>" + obj.To + "</td>";
tableContent += "<td>" + obj.Date + "</td>";
tableContent += "<td>" + obj.Approved + "</td>";
tableContent += "<td>" + obj.Notes + "</td>";
tableContent += "<td>" + obj.Deliverable + "</td>";
tableContent += "</tr>";
});
});
$("#deliverables").append(tableContent);
})
.catch((err) => {
alert("Error: " + err);
console.error(err);
});
});

Just sort the result that you have.
Object.keys(sortedObj).forEach(key => {
tableContent += "<tr>";
tableContent += "<td>" + key + "</td>";
tableContent += "</tr>";
sortedObj[key].sort((a,b)=>{
if (a.Deliverable > b.Deliverable) return 1;
if (a.Deliverable < b.Deliverable) return -1;
return 0;
}).forEach(obj => {
tableContent += "<tr>";
tableContent += "<td> </td>";
tableContent += "<td>" + obj.To + "</td>";
tableContent += "<td>" + obj.Date + "</td>";
tableContent += "<td>" + obj.Approved + "</td>";
tableContent += "<td>" + obj.Notes + "</td>";
tableContent += "<td>" + obj.Deliverable + "</td>";
tableContent += "</tr>";
});
});

Here is the code:
var sortedObj = {}
objItems.forEach(item => {
var program = item.Program;
var deliverable = item.Deliverable;
delete (item.Program); //remove this line to keep the program in the item data
delete (item.Deliverable); //remove this line to keep the deliverable in the item data
if(!sortedObj[program]){
sortedObj[program] = {};
}
if(!sortedObj[program][deliverable]){
sortedObj[program][deliverable] = [];
}
sortedObj[program][deliverable].push(item);
});
Object.keys(sortedObj).forEach((program, index) => {
tableContent += "<tr class='breakrow'>";
tableContent += "<td>" + program + "</td>";
tableContent += "</tr>";
Object.keys(sortedObj[program]).forEach((deliverable, index) => {
tableContent += "<tr class='datarow'>";
tableContent += "<td> </td>";
tableContent += "<td>" + deliverable + "</td>";
tableContent += "</tr>";
sortedObj[program][deliverable].forEach(obj => {
tableContent += "<tr class='subdatarow'>";
tableContent += "<td> </td>";
tableContent += "<td> </td>";
tableContent += "<td>" + obj.To + "</td>";
tableContent += "<td>" + obj.Date + "</td>";
tableContent += "<td>" + obj.Approved + "</td>";
tableContent += "<td>" + obj.Notes + "</td>";
tableContent += "</tr>";
});
});
});
$("#deliverables").append(tableContent);
$('.datarow').hide();
$('.subdatarow').hide();
$('#deliverablesTable').on('click', 'tr.breakrow', function(){
console.log('hello');
$(this).nextUntil('tr.breakrow').slideToggle(200);
});
$(document).on('click','#deliverablesTable tr.datarow', function(){
$(this).nextUntil('tr.breakrow, tr.datarow').slideToggle(200);
});
})

Related

Javascript - How to select "x" row

I have this list made on sweetalert2
*** this is the code ***
function detalleTransf(matricula, bancoorigenTransf, cbu_cta_origen, titular_cta_origen, ultimos_digitos_cta_origen) {
var datosTransferencia = {{ datosTransferencia|json_encode|raw }} ;
let html = "<html><body>"
html += "<div class='table-responsive'><table class='table table-hover table-condensed no-border'>" +
"<tr class='encabezado-tabla'> <td class='text-center'>Seleccionar </td><td class='text-center'> Matricula</td><td class='text-center'> Banco de Origen</td><td class='text-center'>CBU Cuenta Origen</td><td class='text-center'>Titular Cuenta Origen</td><td class='text-center'>Últimos 5 Dígitos Cuenta Origen</td> </tr>";
for (let row of datosTransferencia) {
html += "<tr id='algo'><td class='text-center'><div class='radio'><input type='checkbox' name='check' value='value' id='regular' onclick='prueba()' ><label style='display: none'>" + "</div></label></td>";
html += "<td class='text-center'>" + matricula + "</td>";
html += "<td class='text-center'>" + row.transf_banco + "</td>";
html += "<td class='text-center'>" + row.transf_cbu + "</td>";
html += "<td class='text-center'>" + row.transf_titular + "</td>";
html += "<td class='text-center'>" + row.transf_ctaorigen + "</td></tr>";
}
html += "</table></div>";
html += "</body></html>";
return html;
};
with this function I select each cell of a specific row and insert it into an input field
function test() {
var value1 = document.getElementById("bancoorigenTransf").innerText.replace(/\s+/, "");
var value2 = document.getElementById("cbu_cta_origen").innerText.replace(/\s+/, "");
var value3 = document.getElementById("bancoorigenTransf").innerText.replace(/\s+/, "");
var input = $('#titularorigen666');
var input2 = $('#cbuorigen');
var input3 = $('#bancoorigen');
input.val(input.val() + value1 + ', ');
input2.val(input2.val() + value2 + ', ');
input3.val(input3.val() + value3 + ', ');
return false;
};
The error I have is that it always selects the first row only.
the only solution i could think of is to add a unique id to it in the for loop but i don't know how to do it or if there is a better solution
One answer to this question can be found here, if you are only interested in getting the nth row of a table via JavaScript:
var cells = document.getElementById('table').getElementsByTagName('td');
This will contain all your table cells. Use array notation to access a specific one:
cells[4]
Here's a quick demo which changes the background color:
http://jsfiddle.net/jackwanders/W7RAu/

How to get <TD> title attribute to read array element?

I am trying to get my dynamically created HTML table to display text (contained within an array) on hover of a given cell, using the title attribute, but it will not read the contents of the array and instead reads the array name as a string.
Here is the table generating code and have attempted to add titles to cells of 2 columns currently:
var result = "<table id='dataEditTableid' class='stripe' border=1><thead><tr><th><b>Name</b></th><th><b>7.1</b></th><th><b>7.2</b></th><th><b>7.3</b></th><th><b>7.4</b></th><th><b>7.5</b></th><th><b>7.6</b></th><th><b>8.1</b></th><th><b>8.2</b></th><th><b>8.3</b></th><th><b>8.4</b></th><th><b>8.5</b></th><th><b>8.6</b></th><th><b>9.1</b></th><th><b>9.2</b></th><th><b>9.3</b></th><th><b>9.4</b></th><th><b>9.5</b></th><th><b>9.6</b></th></tr></thead>";
result += "<tbody>";
for (var i=0; i < studentsList.length; i++) {
result += "<tr>";
result += "<td>"+studentsList[i][0]+"</td>";
result += "<td title = studentsList[i][3] style='background-color: "+redBlue(studentsList[i][3])+";' id=" + i+3 + "></td>";
result += "<td title = studentsList[i][4] style='background-color: "+redBlue(studentsList[i][4])+";' id=" + i+4 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][5])+";' id=" + i+5 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][6])+";' id=" + i+6 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][7])+";' id=" + i+7 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][8])+";' id=" + i+8 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][9])+";' id=" + i+9 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][10])+";' id=" + i+10 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][11])+";' id=" + i+11 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][12])+";' id=" + i+12 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][13])+";' id=" + i+13 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][14])+";' id=" + i+14 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][15])+";' id=" + i+15 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][16])+";' id=" + i+16 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][17])+";' id=" + i+17 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][18])+";' id=" + i+18 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][19])+";' id=" + i+19 + "></td>";
result += "<td style='background-color: "+redBlue(studentsList[i][20])+";' id=" + i+20 + "></td>";
result += "</tr>";
}
result += "</tbody></table>";
dataTable.innerHTML = result;
What have I done wrong?
result += "<td title='"+ studentsList[i][4] +"' style='background-color: "+redBlue(studentsList[i][4])+";' id=" + i+4 + "></td>";
you've messed quotations, please replace this with the older ones
also, no need to repeat stuff just add another for loop inside the for:
for (var i = 0; i < studentsList.length; i++) {
result += "<tr>";
result += "<td>" + studentsList[i][0] + "</td>";
result += "<td title='"+ studentsList[i][3] +"' style='background-color: "+redBlue(studentsList[i][3])+";' id=" + i+3 + "></td>";
result += "<td title='"+ studentsList[i][4] +"' style='background-color: "+redBlue(studentsList[i][4])+";' id=" + i+4 + "></td>";
for (var j = 4; j = < 20; i++) {
result += "<td style='background-color: " + redBlue(studentsList[i][j]) + ";' id=" + i + j + "></td>";
}
result += "</tr>";
}

Organize HTML Table (with jQuery?)

I have a searchable HTML table, that retrieves SharePoint list items from a multiple subsites, and everything about it is nearly perfect. The one issue I am facing is that the "Program" item keeps printing every time the function runs through/loops, but I only want it to print the "Program" header/item once, and have the correlating items all print under the one Program header. I will attach below a screenshot of my table and how it prints, as well as my function that reads the information and prints it to the table. Any suggestions/help/advice would be greatly appreciated.
Would I use something along the lines of an if statement?
For example, have the Meeting Minutes and MSR rows for each type of Program print under only one Program.
Actual Result:
**Expected Result**
+------------+----------------------+-----------+------------+--------------+--------------+
| Program | To | Date | Approved | Notes | Deliverable |
+------------+----------------------+-----------+------------+--------------+--------------+
| Program 1 | example#example.com | 12/23/2018| Yes | Example Notes| MSR |
| | example#example.com | 03/30/2020| Yes | Example Notes| Meeting Mins |
+------------+----------------------+-----------+------------+--------------+--------------+
| Program 2 | example#example.com | 12/23/2018| Yes | Example Notes| MSR |
| | example#example.com | 12/03/2017| Yes | Example Notes| Meeting Mins |
+------------+----------------------+-----------+------------+--------------+--------------+
| Program 3 | example#example.com | 04/17/2020| Yes | Example Notes| MSR |
| | example#example.com | 03/30/2020| No | Example Notes| Meeting Mins |
+------------+----------------------+-----------+------------+--------------+--------------+
Here is my code:
.then(([r1, r2, r3]) => {
const objItems = r1.concat(r2,r3);
console.log(objItems);
var tableContent =
'<table id="deliverablesTable" style="width:100%" border="1 px"><thead><tr><td><strong>Program</strong></td>' +
"<td><strong>To</strong></td>" +
"<td><strong>Date Submitted</strong></td>" +
"<td><strong>Approved</strong></td>" +
"<td><strong>Notes</strong></td>" +
"<td><strong>Deliverable</strong></td>" +
"</tr></thead><tbody>";
for (var i = 0; i < objItems.length; i++) {
if (objItems.Program == "1"){
tableContent += "<tr>";
tableContent += "<td>" + objItems[i].Program + "</td>";
tableContent += "</tr>";
tableContent += "<tr>";
tableContent += "<td> </td>";
tableContent += "<td>" + objItems[i].To + "</td>";
tableContent += "<td>" + objItems[i].Date + "</td>";
tableContent += "<td>" + objItems[i].Approved + "</td>";
tableContent += "<td>" + objItems[i].Notes + "</td>";
tableContent += "<td>" + objItems[i].Deliverable + "</td>";
tableContent += "</tr>";
}
else if (objItems.Program == "2"){
tableContent += "<tr>";
tableContent += "<td>" + objItems[i].Program + "</td>";
tableContent += "</tr>";
tableContent += "<tr>";
tableContent += "<td> </td>";
tableContent += "<td>" + objItems[i].To + "</td>";
tableContent += "<td>" + objItems[i].Date + "</td>";
tableContent += "<td>" + objItems[i].Approved + "</td>";
tableContent += "<td>" + objItems[i].Notes + "</td>";
tableContent += "<td>" + objItems[i].Deliverable + "</td>";
tableContent += "</tr>";
}
else if (objItems.Program == "3"){
tableContent += "<tr>";
tableContent += "<td>" + objItems[i].Program + "</td>";
tableContent += "</tr>";
tableContent += "<tr>";
tableContent += "<td> </td>";
tableContent += "<td>" + objItems[i].To + "</td>";
tableContent += "<td>" + objItems[i].Date + "</td>";
tableContent += "<td>" + objItems[i].Approved + "</td>";
tableContent += "<td>" + objItems[i].Notes + "</td>";
tableContent += "<td>" + objItems[i].Deliverable + "</td>";
tableContent += "</tr>";
}
}
$("#deliverables").append(tableContent);
})
.catch((err) => {
alert("Error: " + err);
console.error(err);
});
});
[1]: https://i.stack.imgur.com/ULOMF.png
var tableData =
[{'program': 'Program 1', 'To': 'example1', Date: '8/5', Approved: 'Yes', Notes: 'Note', Deliverable: 'Deliverable'},
{'program': 'Program 1', 'To': 'example2', Date: '8/5', Approved: 'Yes', Notes: 'Note', Deliverable: 'Deliverable'},
{'program': 'Program 2', 'To': 'example3', Date: '8/5', Approved: 'No', Notes: 'Note', Deliverable: 'Deliverable'},
{'program': 'Program 3', 'To': 'example4', Date: '8/5', Approved: 'Yes', Notes: 'Note', Deliverable: 'Deliverable'},
{'program': 'Program 3', 'To': 'example4', Date: '8/5', Approved: 'Yes', Notes: 'Note', Deliverable: 'Deliverable'},
{'program': 'Program 3', 'To': 'example4', Date: '8/5', Approved: 'Yes', Notes: 'Note', Deliverable: 'Deliverable'}]
//Fake loadData(...)
Promise.all(tableData)
.then((r1) => {
const objItems = r1;
makeTable(objItems);
})
function makeTable(tableData){
var group = {};
for(var d of tableData){
if(group[d.program]){
group[d.program].push(d);
} else {
group[d.program] = [d];
}
}
var tableContent = ''; // I put the table in the html but you can populate it here
for (var prop in group) {
tableContent += "<tr>";
tableContent += "<td rowspan=\""+ group[prop].length +"\">" + prop + "</td>";
tableContent += "<td>" + group[prop][0].To + "</td>";
tableContent += "<td>" + group[prop][0].Date + "</td>";
tableContent += "<td>" + group[prop][0].Approved + "</td>";
tableContent += "<td>" + group[prop][0].Notes + "</td>";
tableContent += "<td>" + group[prop][0].Deliverable + "</td>";
tableContent += "</tr>";
for(var i = 0; i < group[prop].length - 1; i++){
tableContent += "<tr>";
tableContent += "<td>" + group[prop][i+1].To + "</td>";
tableContent += "<td>" + group[prop][i+1].Date + "</td>";
tableContent += "<td>" + group[prop][i+1].Approved + "</td>";
tableContent += "<td>" + group[prop][i+1].Notes + "</td>";
tableContent += "<td>" + group[prop][i+1].Deliverable + "</td>";
tableContent += "</tr>";
}
}
$("#deliverablesTable").append(tableContent);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="deliverablesTable" style="width:100%" border="1 px">
<thead>
<tr>
<td><strong>Program</strong></td>
<td><strong>To</strong></td>
<td><strong>Date</strong></td>
<td><strong>Approved</strong></td>
<td><strong>Notes</strong></td>
<td><strong>Deliverable</strong></td>
</tr></thead><tbody>

How to wrap code in a function correctly?

I have a code that automatically creates a table for me. It gathers information from a saved file, however, I have two of these files and currently can call one at the time. How can I possibly wrap this code in a function so that there are two calls on the same code with different information that will be put in it? So right now I am using getElementById on file "house-data" but I also want to have this same js on a file "senate-data"
I thought of creating some sort of if statement where if(you have one file): do this
else
do that. But this method doesnt work.
var table = "";
var cols = 1;
var members = data.results[0].members;
var rows = members.length;
table += "<tr>" +
"<th>" + "Full Name" + "</th>" +
"<th>" + "Party" + "</th>" +
"<th>" + "State" + "</th>" +
"<th>" + "Seniority"+ "</th>" +
"<th>" + "Total Votes"+ "</th>" + "</tr>";
for (var r = 0; r < rows; r++) {
table += "<tr>";
for (var c = 0; c < cols; c++) {
table +=
"<td>" + members[r].first_name +", "+
(members[r].middle_name || " ") +" "+
members[r].last_name + "</td>";
table += "<td>" + members[r].party + "</td>" + "<td>" + members[r].state + "</td>" + "<td>" + members[r].seniority + "</td>";
if (members[r].votes_with_party_pct === undefined) {
table += "<td>" + "-" + "</td>"
} else {
table += "<td>" + members[r].votes_with_party_pct + "%" + "</td>"
}
}
table += "<tr>";
}
document.getElementById("house-data").innerHTML = JSON.stringify(table);
function tableCreator(elementID, data) {
[...]
document.getElementById(elementID)[...]
}
above will work for you and keep in mind to check
var members = data.results[0].members;
is available before going to for loop

HTML- Header for Dynamic Table

This is my current table-
txt += "<table border='2'>";
for (x in myObj) {
txt += "<tr>"
txt += "<td>" + myObj[x].friend_id + "</td>";
txt += "<td>" + myObj[x].birth_date + "</td>";
txt += "<td>" + myObj[x].first_name + "</td>";
txt += "<td>" + myObj[x].last_name + "</td>";
txt += "<td>" + myObj[x].gender + "</td>";
txt += "<td>" + myObj[x].phone+ "</td>";
txt += "</tr>"
I'm populating it with JSON output, which works fine. However, I don't know how to add the header to the table. I tried adding the header out of the for loop, but it wouldn't align with the table in the loop. How do I connect both?
Current table- https://imgur.com/a/Fo7OdfX
txt += "<table border='2'>";
txt += "<tr>"
txt += "<th>Friend Id</th>";
txt += "<th>Birth Date</th>";
txt += "<th>First Name</th>";
txt += "<th>Last Name</th>";
txt += "<th>Gender</th>";
txt += "<th>Phone</th>";
txt += "</tr>"
for (x in myObj) {
txt += "<tr>"
txt += "<td>" + myObj[x].friend_id + "</td>";
txt += "<td>" + myObj[x].birth_date + "</td>";
txt += "<td>" + myObj[x].first_name + "</td>";
txt += "<td>" + myObj[x].last_name + "</td>";
txt += "<td>" + myObj[x].gender + "</td>";
txt += "<td>" + myObj[x].phone+ "</td>";
txt += "</tr>"
}

Categories