Reputation: 5954
It's been a while since I've coded, so I'm kind of at a loss right now.
I'm populating a table (or rather a grid) on my website with data from a database. Below is the structure of the code:
#table {
display: grid;
}
<div id="table">
<div class="container" id="1340firstitem">
<text class="channel-pop"> 100,022 </text>
<text class="channel" > @1340firstitem </text>
<text class="hashtag-pop"> 1,100 </text>
</div>
<div class="container" id="second_item">
<text class="channel-pop"> 555 </text>
<text class="channel" > @second_item </text>
<text class="hashtag-pop"> 49 </text>
</div>
<div class="container" id="3rd.item">
<text class="channel-pop"> 100,022 </text>
<text class="channel" > @3rd.item </text>
<text class="hashtag-pop"> 49 </text>
</div>
</div>
Whereby the information is displayed on the page like so:
______C1____|________C2________|____C3______
100,022 | @1340firstitem | 1,100
555 | @second_item | 49
100,022 | @3rd.item | 49
Whereas the content of C2
or class="channel"
elements is always unique, sometimes the content of class="channel-pop"
and class="hashtag-pop"
elements will be the same.
I would like to be able to sort and re-sort the data in the grid alphabetically based on the value of class="channel"
(A-Z and Z-A) and numerically based on the values of class="channel-pop"
and class="hashtag-pop"
(0-1 and 1-0). However, I'm having a brain fart as to how I would go about doing this.
Eventually the database will become quite dense, so I need to do this as efficiently as possible -- not looping through nested arrays or using loop within loops within loops...
Since the data in C1
and C3
is not always unique, I know I need to map the children elements or their content to the parent container
, which I can do using the data-
attribute, objects in JS, the map object, etc.
I'm not entirely familiar with map objects, so currently, when the page loads, I'm adding data-
attributes to the parent container like so:
<div class="container" id="1340firstitem"
data-channel-pop="100,022"
data-hashtag-pop="1,100"
>
<text class="channel-pop"> 100,022 </text>
<text class="channel" > @1340firstitem </text>
<text class="hashtag-pop"> 1,100 </text>
</div>
However, of course when I loop through the container
class and create an array of these data-
attributes, the value of the data-
is once again disassociated from the parent element.
I haven't coded in a while, so I'm struggling to wrap my head around this right now. Any help would be greatly appreciated.
Upvotes: 1
Views: 267
Reputation: 19344
However, of course when I loop through the container class and create an array of these data- attributes, the value of the data- is once again disassociated from the parent element.
This looks like a design error. Create an array of sortable container object data, say like:
const gridRows = Array.from(
document.getElementById("table")
.querySelectorAll(".container")
).map ( container => [
container,
container.children[0].textContent.trim(),
container.children[1].textContent.trim(),
container.children[2].textContent.trim()
]
);
This is an example only* and creates an array of inner arrays of the form
[ containerDOMobject, columnOneText, columnTwoText, columnThreeText]
(*The mapping function could be optimized to avoid creating three children node lists, the mapped element is presented as an array for simplicity.)
Sort the gridRows
array in any way needed. When replacing a container object in the DOM, using the DOM object reference value from the sorted gridRows
array, you don't need to remove it first - appending (to the same parent in this case) will move an existing DOM object rather than duplicating it.
A variation of gridRows
preparation could convert numeric entries into numbers for sorting purposes. The reason for creating gridRows
in the first place was to simplify and expedite sorting - as one commentator noted, there are multiple ways of achieving your goal.
Updating the display is done by appending container
items to the #table
element in sorted order. It retains use of <text>
elements but not display:grid
layout. How to sort the contents of a display:grid
element merits a separate question.
document.addEventListener("DOMContentLoaded", function(event) {
let ascending = 1;
let sortColumn = undefined;
let uniqueColumn = document.getElementById("channelColumn").dataset.value;
const gridRows = Array.from(
document.getElementById("table")
.querySelectorAll(".container")
).map ( container =>
{
const children = container.children;
let data = [
container,
children[0].textContent.trim(),
children[1].textContent.trim(),
children[2].textContent.trim()
];
for( var i of [1,3]) {
data[i] = Number( data[i].replace(",", ""));
}
return data;
});
function compareRows( aRow, bRow) {
let a = aRow[sortColumn];
let b = bRow[sortColumn];
if( a > b) {
return ascending;
}
if( a < b) {
return -ascending;
}
a = aRow[uniqueColumn];
b = bRow[uniqueColumn];
if( a > b) {
return ascending;
}
if( a < b) {
return -ascending;
}
return 0;
}
function sortGrid( event) {
let target = event.target;
let column = target.dataset.column;
let table = document.getElementById("table");
if( column) {
ascending = column === sortColumn ? -ascending : 1;
sortColumn = column;
gridRows.sort( compareRows);
gridRows.forEach( data => table.appendChild(data[0]));
}
}
document.getElementById("sortBy").addEventListener("click", sortGrid);
});
#table: {
}
#sortBy {
font-weight: bold;
color: teal;
border-bottom: medium solid grey;
cursor: default;
}
text {
display: inline-block;
width: 30%;
text-align: right;
}
<div id="table">
<div id="sortBy"><!-- table header -->
<text data-column="1">channel-pop</text>
<text id="channelColumn" data-column="2">channel</text>
<text data-column="3">hashtag-pop</text>
</div>
<div class="container" id="1340firstitem">
<text class="channel-pop"> 100,022 </text>
<text class="channel" > @1340firstitem </text>
<text class="hashtag-pop"> 1,100 </text>
</div>
<div class="container" id="second_item">
<text class="channel-pop"> 555 </text>
<text class="channel" > @second_item </text>
<text class="hashtag-pop"> 49 </text>
</div>
<div class="container" id="3rd.item">
<text class="channel-pop"> 100,022 </text>
<text class="channel" > @3rd.item </text>
<text class="hashtag-pop"> 49 </text>
</div>
</div>
Upvotes: 1