I want to add arrow bottons/icons to my header on an HTML table. Right now, once you click anywhere on the header it sorts my data on the table without displaying any arrows (see screenshots below)
Ascending sort
Descending sort
I googled and tested like 5 hours already, but I could not find what I was looking for. I want the header to display a drop-up button/icon when the table is sorted in descending order and be a drop-down when in ascending order. I hope this makes sense.
Here is my CSS/JS/HTML for your reference. I don’t look for the complete solution code, but am just looking for hints or any directions that I can try on my own. Thank you for the help in advance.
JS
avascript: (function () {
const isEmptyOrNaN = (obj) => obj === "" || isNaN(obj);
const getCellValueInColumn = (tr, columnIdx) =>
tr.children[columnIdx].innerText || tr.children[columnIdx].textContent;
const compareCellValues = (cellValue1, cellValue2) => {
return isEmptyOrNaN(cellValue1) || isEmptyOrNaN(cellValue2)
? cellValue1.toString().localeCompare(cellValue2)
: cellValue1 - cellValue2;
};
const compareFnFactory = (columnIdx, ascending) => (firstEl, secondEl) => {
const cellValue1 = getCellValueInColumn(firstEl, columnIdx);
const cellValue2 = getCellValueInColumn(secondEl, columnIdx);
return ascending
? compareCellValues(cellValue1, cellValue2)
: compareCellValues(cellValue2, cellValue1);
};
document.querySelectorAll("th").forEach((th) =>
th.addEventListener("click", () => {
const table = th.closest("table");
const tbody = table.querySelector("tbody");
const columnIdx = Array.from(th.parentNode.children).indexOf(th);
const compareFn = compareFnFactory(columnIdx, (this.ascending = !this.ascending));
Array.from(tbody.querySelectorAll("tr"))
.sort(compareFn)
.forEach((tr) => tbody.appendChild(tr));
})
);
})();
CSS
tr:nth-child(even){
background-color: var(--bs-table-bg);
}
tr:nth-child(odd){
background-color: var(--bs-table-active-bg);
}
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--JQuery-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!--bootstrap v5.1-->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<!--Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!--Axios-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!--Custom CSS-->
<link rel="stylesheet" href="style.css">
<!--tablesorter.js-->
<title>CONFIDENCIAL - users</title>
</head>
<body>
<div class="mt-4 container" id="app">
<table class="table table-success table-striped">
<thead>
<tr>
<th>#
</th>
<th>Name
</th>
<th>Title
</th>
<th>Body
</th>
</tr>
</thead>
<tbody>
<tr v-for="post, index in posts" :key = "post.userId">
<td scope="row">{{ index + 1 }}</td>
<td>{{ post.id }}</td>
<td>{{ post.title }}</td>
<td>{{ post.body }}</td>
</tr>
</tbody>
</table>
</div>
<script>
new Vue({
el:"#app",
data: {
posts: []
},
created(){
axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response =>
this.posts = response.data
)
.catch(error =>
console.log(error)
)
}
})
</script>
<!--custom js-->
<script src="main.js"></script>
</body>
</html>