This question already has answers here:
Sorting an Array of Objects by two Properties
(5 answers)
Closed last year.
How can i sort my table by two columns ( Name, Available) on page load? I can use vanilla js
<table class="table_sort">
<thead>
<tr>
<th class="sorted-asc">Name</th>
<th>Genre</th>
<th>Publish year</th>
<th>Quanity</th>
<th class="available">Available</th>
</tr>
</thead>
<tbody id="tbody">
<tr>
<td>aname1</td>
<td>genre1</td>
<td>year1</td>
<td>quantity1</td>
<td>2</td>
</tr>
<tr>
<td>name1</td>
<td>genre1</td>
<td>year1</td>
<td>quantity1</td>
<td>1</td>
</tr>
<tr>
<td>aname1</td>
<td>genre1</td>
<td>year1</td>
<td>quantity1</td>
<td>10</td>
</tr>
<tr>
<td>aname1</td>
<td>genre1</td>
<td>year1</td>
<td>quantity1</td>
<td>6</td>
</tr>
</tbody>
</table>
I try to sort my table by two columns: Name, Available but it does not work.
document.addEventListener('DOMContentLoaded', () => {
const table = document.querySelector('.table_sort');
const indexToSorting = [...table.tHead.rows[0].cells].findIndex(cell => cell.classList.contains('sorted-asc'));
const availableIndexes = [...table.tHead.rows[0].cells].findIndex(cell => cell.classList.contains('available'));
const sortedRows = [...table.tBodies[0].rows].sort((rowA, rowB) => {
let cellC;
let cellD;
const sortedRowsByAvailable = [...table.tBodies[0].rows].sort((rowC, rowD) => {
cellC = rowC.cells[availableIndexes].innerText;
cellD = rowD.cells[availableIndexes].innerText;
const availableComparison = cellC.localeCompare(cellD);
return availableComparison;
});
const cellA = rowA.cells[indexToSorting].innerText;
const cellB = rowB.cells[indexToSorting].innerText;
const nameComparison = cellA.localeCompare(cellB);
return nameComparison !== 0 ? nameComparison : sortedRowsByAvailable
});
table.tBodies[0].append(...sortedRows);
});
My table is sorted by name, but i need to sort it by columns: name, available. Where is my mistake? I don't understand, please, help me
TBH, I didn't understand why you did cellA - cellB, but you need to add a comparison for Available cells in case cellA and cellB are equal.
const rowAAvailable = rowA.cells[indexToSorting].innerText;
const rowBAbailable = rowB.cells[indexToSorting].innerText;
const nameComparison = cellA.localeCompare(cellB);
const availableComparison = rowAAvailable.localeCompare(rowBAbailable); // sorry for terrible naming, but you get the idea
return nameComparison !== 0 ? nameComparison : availableComparison
This will sort your table by name as the first priority and available the second one.
Related
I'm trying to add a sortable table to my site but I'm having issues sorting columns with varying digit entries. It works fine when all numbers are the same number of digits in length.
However, when I change the number of digits, the sort function seems to break and sorts them out of order.
The code below is a simple example of this. The table I am working with is much larger and more interesting than people, their jobs and age.
Here is my HTML:
<!DOCTYPE html>
<head>
<title>Sorting Tables w/ JavaScript</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="utf-8" />
</head>
<body>
<table class="table-sortable">
<thead>
<tr>
<th>Rank</th>
<th>Name</th>
<th>Age</th>
<th>Occupation</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Dom</td>
<td>5</td>
<td>Web Developer</td>
</tr>
<tr>
<td>2</td>
<td>Rebecca</td>
<td>29</td>
<td>Teacher</td>
</tr>
<tr>
<td>3</td>
<td>John</td>
<td>100</td>
<td>Civil Engineer</td>
</tr>
<tr>
<td>4</td>
<td>Andre</td>
<td>20</td>
<td>Dentist</td>
</tr>
</tbody>
</table>
<script src="./src/tablesort.js"></script>
</body>
JS:
function sortTableByColumn(table, column, asc = true) {
const dirModifier = asc ? 1 : -1;
const tBody = table.tBodies[0];
const rows = Array.from(tBody.querySelectorAll("tr"));
// Sort each row
const sortedRows = rows.sort((a, b) => {
const aColText = a.querySelector(`td:nth-child(${ column + 1 })`).textContent.trim();
const bColText = b.querySelector(`td:nth-child(${ column + 1 })`).textContent.trim();
return aColText > bColText ? (1 * dirModifier) : (-1 * dirModifier);
});
// Remove all existing TRs from the table
while (tBody.firstChild) {
tBody.removeChild(tBody.firstChild);
}
// Re-add the newly sorted rows
tBody.append(...sortedRows);
// Remember how the column is currently sorted
table.querySelectorAll("th").forEach(th => th.classList.remove("th-sort-asc", "th-sort-desc"));
table.querySelector(`th:nth-child(${ column + 1})`).classList.toggle("th-sort-asc", asc);
table.querySelector(`th:nth-child(${ column + 1})`).classList.toggle("th-sort-desc", !asc);
}
document.querySelectorAll(".table-sortable th").forEach(headerCell => {
headerCell.addEventListener("click", () => {
const tableElement = headerCell.parentElement.parentElement.parentElement;
const headerIndex = Array.prototype.indexOf.call(headerCell.parentElement.children, headerCell);
const currentIsAscending = headerCell.classList.contains("th-sort-asc");
sortTableByColumn(tableElement, headerIndex, !currentIsAscending);
});
});
Any help on this would be much appreciated!! Thank you all so much for your help on this!
To sort by numeric value:
return parseFloat(aColText) > parseFloat(bColText) ? (1 * dirModifier) : (-1 * dirModifier);
Otherwise, sort will be by string value ("2" is bigger than "10").
In general, to sort by numeric value:
array.sort((a,b)=>parseFloat(a)<parseFloat(b)?-1:1)
What I want to do is use Propublica's nonprofit API to pull in information about various nonprofits and display certain attributes in a table.
Right now, I'm fetching an object:
const [ orgs, setOrgs ] = useState({})
const fetchOrgs = async () => {
const result = await Axios.get(`${API_URL}?state%5Bid%5D=${query}`)
setOrgs(result.data.organizations)
}
According to their API, organization objects are like this:
{
"organization":{
"id":142007220,
"ein":142007220,
"name":"PRO PUBLICA INC",
"careofname":null,
"address":"155 AVE AMERICA 13 FL",
"city":"NEW YORK",
"state":"NY",
"zipcode":"10013-0000",
"exemption_number":0,
"subsection_code":3,
"affiliation_code":3,
"classification_codes":"1000",
"ruling_date":"2008-02-01",
"deductibility_code":1,
"foundation_code":15,
"activity_codes":"0",
"organization_code":1,
"exempt_organization_status_code":1,
"tax_period":"2018-12-01",
"asset_code":8,
"income_code":8,
"filing_requirement_code":1,
"pf_filing_requirement_code":0,
"accounting_period":12,
"asset_amount":40988939,
"income_amount":27237842,
"revenue_amount":26685933,
"ntee_code":"A20",
"sort_name":null,
"created_at":"2020-04-13T21:42:55.607Z",
"updated_at":"2020-04-13T21:42:55.607Z",
"data_source":null,
"have_extracts":null,
"have_pdfs":null
},
This is my current function, which is not working:
const displayTable = () => {
return (
<Table striped border='true' hover='true' responsive='true'>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>State</th>
<th>City</th>
<th>NTEE</th>
<th>Income</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>Test</td>
<td>Test</td>
<td>Test</td>
<td>Test</td>
<td><a href=' '>Link</a></td>
</tr>
{Object.keys(orgs).map(({name, state, ntee_code, income_amount}, i) => (
<tr key={i}>
<td>{i + 1}</td>
<td>{name}</td>
<td>{state}</td>
<td>{ntee_code}</td>
<td>{income_amount}</td>
</tr>
))}
</tbody>
</Table>
)
}
When I run this, I get the test row, and then many rows of empty cells. Only the "#" column has anything, since it's just the index value. What am I doing wrong here? Any help would be much appreciated, I've only just started learning React and JS.
here is a working example:
return (
<div>
<h1>Organizations:</h1>
<table style={{ width: '100%', textAlign: 'center', border: 'solid 1px' }}>
<thead>
<th>Index</th><th>Name</th><th>State</th><th>ntee_code</th><th>income_amount</th>
</thead>
<tbody>
{orgs.map((organization, i) => {
const org = organization.organization;
return (
<tr>
<td>{i}</td><td>{org.name}</td><td>{org.state}</td><td>{org.ntee_code}</td><td>{org.income_amount}</td>
</tr>
)
})}
</tbody>
</table>
</div>
)
I'm posting just the returned markup as I understood you have no problem with fetching the data, and you just don't know how to display.
Your solution had the right idea of iterating over the organization array to create <tr>s. But you didn't need the Object.keys() to access the values. You first need to iterate over the objects in the array, and then drill down each object using the . syntax: const org = organization.organization; and then e.g org.name.
Note that each of your objects actually has only one field, i.e organization, so you first need to drill into it and only then you can get the values further down the object tree. If you want to deconstruct the object in map() you can, and again you had the right idea about how it's done, you just got the layer wrong. So you can do
{orgs.map(({organization}, i) => {
const { name, state, ntee_code, income_amount } = organization;
return (
<tr>
<td>{i}</td><td>{name}</td><td>{state}</td><td>{ntee_code}</td><td>{income_amount}</td>
</tr>
)
})}
I hope it can help and it's all clear.
Good luck!
I want to display a Array of names in a table. ist like a timetable and i have a sort-button because if i want to add a new Student, the Student should be classified at the right place.
My Array contains this values
Benj
Zebra
Yves
Anna
but if i press the sort button the output is like this
Zebra
Yves
Anna
Benj
That dosent make sense ist not ascending and not descending
Here is the code
function sort(){
students.sort();
for(var i = 0;i<students.length+1;i++){
if(i!=0){
alert(students[i-1].innerHTML);
<!table.rows[i].cells[0].innerHTML=students[i1].innerHTML;>
}
}
}
If you're trying to sort the rows of an existing table - here's a better way
document.getElementById('sort1').addEventListener('click', () => {
let tableBody = document.querySelector('#table>tbody');
let rows = [...tableBody.querySelectorAll('#table>tbody>tr')];
rows
.sort((a, b) => a.cells[0].textContent.localeCompare(b.cells[0].textContent))
.forEach(row => tableBody.append(row));
});
document.getElementById('sort2').addEventListener('click', () => {
let tableBody = document.querySelector('#table>tbody');
let rows = [...tableBody.querySelectorAll('#table>tbody>tr')];
rows
.sort((a, b) => a.cells[2].textContent.localeCompare(b.cells[2].textContent))
.forEach(row => tableBody.append(row));
})
<table id="table">
<tbody>
<tr>
<td>Delta</td>
<td>Alpahbetically 4th</td>
<td>Rank 2nd</td>
</tr>
<tr>
<td>Bravo</td>
<td>Alpahbetically 2nd</td>
<td>Rank 1st</td>
</tr>
<tr>
<td>Charlie</td>
<td>Alpahbetically 3rd</td>
<td>Rank 4th</td>
</tr>
<tr>
<td>Alpha</td>
<td>Alpahbetically 1st</td>
<td>Rank 3rd</td>
</tr>
</tbody>
</table>
<button id="sort1">Sort by name</button>
<button id="sort2">Sort by rank</button>
Active learner here, trying to figure out how to create a JSON object out of HTML table. I only want the value of one specific TD and want to give each value an incrementing number as a key. I'd like an output like below. My table has a TD for the city names, but it does not have one with a incrementing numerical value so I'd need to add that another way.
{
"mycities" : [
{
"Seattle" : "1",
"Chicago" : "2",
"New York" : "3"
"Pitt" : "4",
"LA" : "5",
"Fresno" : "6"
},
]
}
Here is what my table looks like:
<table>
<thead>
<tr>
<th>city name</th>
<th>other city info</th>
</tr>
</thead>
<tbody>
<tr>
<td>Seattle</td>
<td>Lots of rain</td>
</tr>
etc,etc,etc
</tbody>
</table>
I've tried using a replacer function but haven't got it figured out after much googling. Any help is appreciated!
$(document).ready(function(){
$("body").on("click",".submitButtonPri",function(){
count= 1;
function replacer(key, value) {
if (typeof value === 'string') {
return count;
}
return value;
}
var myRows = [];
var $headers = $(".rightDash > table thead th");
var $rows = $(".rightDash > table tbody tr").each(function(index) {
$cells = $(this).find("td.titlePri");
myRows[index] = {};
$cells.each(function(cellIndex) {
myRows[index][$($cells[cellIndex]).text()] = $(this).text();
});
count++;
});
var myObj = {};
myObj.myrows = myRows;
console.log(JSON.stringify(myObj,replacer));
});
});
Use reduce to iterate over the trs in the body, using the text content of the first td in the tr as the city name. The third argument to the function provided to reduce represents the iteration index:
const cityData = [...document.querySelectorAll('tbody > tr')]
.reduce((a, tr, i) => {
a[tr.children[0].textContent] = i + 1;
return a;
}, {});
console.log(
{ mycities: [
cityData
]}
);
<table>
<thead>
<tr>
<th>city name</th>
<th>other city info</th>
</tr>
</thead>
<tbody>
<tr>
<td>Seattle</td>
<td>Lots of rain</td>
</tr>
<tr>
<td>Chicago</td>
<td>Lots of rain</td>
</tr>
<tr>
<td>New York</td>
<td>Lots of rain</td>
</tr>
</tbody>
</table>
You can start with this simple script:
$('td').each(function(index, obj) {console.log(index, $(this).html())});
It returns all what you need and you just need assemble JSON by any way
$(function() {
var companyId = 1740963;
JA.get('api/' + companyId + '/Transaction', function(data) {
if (!data)
return;
var items = data.Items;
if (!items)
return;
for (var i = 0; i < items.length; i++) {
var expense = items[i];
JA.renderTemplateFromPath('expenseListRow', items[i], function(template) {
var $template = $(template);
$('#expenseListBody').append($template);
$template.find('.expenseDate p').html(function(index, value) {
return moment(value, "YYYY-MM-DDTHH:mm:ss").format("DD/MM/YYYY");
});
})
}
});
})
<table id="expenseList">
<tr id="expenseListHead">
<th id="numberID">Number</th>
<th>Date</th>
<th>Name</th>
<th>Description</th>
<th>Reference</th>
<th class="alignRight">Amount</th>
<th class="alignRight"></th>
</tr>
<tbody id="expenseListBody">
<tr class="expenseListRow">
<td></td>
<td class="expenseDate"></td>
<td></td>
<td></td>
<td></td>
<td class="alignRight"></td>
<td class="alignRight"></td>
</tr>
</tbody>
</table>
As you can see in the image, there are multiple numbers in random order being pulled from an API, the list carry's on for a while.
What I am wondering is if anyone could help me work out how to sort these numbers in ascending order (starting from 1) and so on, instead of it adding them randomly, like I said this data is being pulled from an API that has been written so I'm struggling to work out how to do this. If anymore info is needed to help answer let me know. Thanks in advance.
If your list contains only numbers you can use the sort function available with Array. just call
var sortedList = yourList.sort();
If its an array of objects and the numbers are inside as a field then you can override the sort function as mentioned here