data = [
{
"name": "Dave",
"dept": "Marketing",
"region": "South",
"items": 28
},
{
"name": "Amy",
"dept": "IT",
"region": "West",
"items": 46
},
{
"name": "John",
"dept": "Sales",
"region": "North",
"items": 35
},
{
"name": "Sarah",
"dept": "Communications",
"region": "North",
"items": 13
}
]
drawTable(data)
sortTable(data)
function drawTable(data) {
// not working
// when redrawing table, trying to re-initialize sort function
sortTable(data)
d3.select('#data-table').remove()
let table = d3.select('#table').append('div').attr('id', 'data-table')
let row = table.selectAll('.row')
.data(data)
.enter()
.append('div')
.attr('class', 'row')
let grid = row
.append('div')
.attr('class', 'grid')
let name = grid.append('div')
.attr('class', 'box')
.html(d => d.name)
let dept = grid.append('div')
.attr('class', 'box')
.html(d => d.dept)
let region = grid.append('div')
.attr('class', 'box')
.html(d => d.region)
let items = grid.append('div')
.attr('class', 'box')
.html(d => d.items)
}
function sortTable(data) {
d3.selectAll(".name,.dept,.region,.items").on('click', function () {
let sortWhich = d3.select(this).attr("class")
console.log('sortWhich', sortWhich)
let tableSort
if (sortWhich == "name") {
tableSort = data.sort((a, b) => d3.ascending(a.name, b.name))
} else if (sortWhich == "dept") {
tableSort = data.sort((a, b) => d3.ascending(a.dept, b.dept))
} else if (sortWhich == 'region') {
tableSort = data.sort((a, b) => d3.ascending(a.region, b.region))
} else {
tableSort = data.sort((a, b) => d3.ascending(a.items, b.items))
}
// Can I combine the above and pass a variable to a sort function? This is not working:
// let tableSort = data.sort((a, b) => a.sortWhich - b.sortWhich)
drawTable(tableSort)
})
}
html,
body {
height: 100%;
margin: 0;
}
.grid {
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.grid>div {
display: flex;
flex-basis: calc(100%/4 - 28px);
justify-content: center;
flex-direction: column;
padding: 10px;
}
.box {
margin: 0;
}
.box {
color: #000;
border: .5px solid #ccc;
}
.hrbox {
background-color: #333;
color: #fff;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
<div id="table">
<div class="grid">
<div class="box hrbox name">
<div>name</div>
</div>
<div class="box hrbox dept">
<div>dept</div>
</div>
<div class="box hrbox region">
<div>region</div>
</div>
<div class="box hrbox items">
<div>items</div>
</div>
</div>
<div id="data-table"></div>
</div>
</body>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
I created a flexbox table using d3.js that pulls json data to populate it. I want to be able to sort each column by its header row, and I wrote a sort function for that. However, I'm only able to sort one column at a time right now. Then if I refresh the page, I can sort a different column. I want to be able to switch without needing to refresh the page. So- sort by name, then decide to sort by items, then region, to see different views of the data. What am I missing?
I'd appreciate any feedback.
[I'd also like to just have one sort function that I pass a variable to instead of having all those conditionals. I'm not sure if it's possible. (Definitely not my main concern.) But putting it out there]
Thanks!
CodePudding user response:
If you look at the console you'll see that sortWhich
is always something like "box hrbox whatever"
, and because of that all conditions will fail and the code will go to the else
at the bottom.
A simplest solution is using includes()
:
if (sortWhich.includes("name")) etc...
Here is your code with that change:
data = [{
"name": "Dave",
"dept": "Marketing",
"region": "South",
"items": 28
},
{
"name": "Amy",
"dept": "IT",
"region": "West",
"items": 46
},
{
"name": "John",
"dept": "Sales",
"region": "North",
"items": 35
},
{
"name": "Sarah",
"dept": "Communications",
"region": "North",
"items": 13
}
]
drawTable(data)
sortTable(data)
function drawTable(data) {
// not working
// when redrawing table, trying to re-initialize sort function
sortTable(data)
d3.select('#data-table').remove()
let table = d3.select('#table').append('div').attr('id', 'data-table')
let row = table.selectAll('.row')
.data(data)
.enter()
.append('div')
.attr('class', 'row')
let grid = row
.append('div')
.attr('class', 'grid')
let name = grid.append('div')
.attr('class', 'box')
.html(d => d.name)
let dept = grid.append('div')
.attr('class', 'box')
.html(d => d.dept)
let region = grid.append('div')
.attr('class', 'box')
.html(d => d.region)
let items = grid.append('div')
.attr('class', 'box')
.html(d => d.items)
}
function sortTable(data) {
d3.selectAll(".name,.dept,.region,.items").on('click', function() {
let sortWhich = d3.select(this).attr("class")
console.log('sortWhich', sortWhich)
let tableSort
if (sortWhich.includes("name")) {
tableSort = data.sort((a, b) => d3.ascending(a.name, b.name))
} else if (sortWhich.includes("dept")) {
tableSort = data.sort((a, b) => d3.ascending(a.dept, b.dept))
} else if (sortWhich.includes('region')) {
tableSort = data.sort((a, b) => d3.ascending(a.region, b.region))
} else {
tableSort = data.sort((a, b) => d3.ascending(a.items, b.items))
}
// Can I combine the above and pass a variable to a sort function? This is not working:
// let tableSort = data.sort((a, b) => a.sortWhich - b.sortWhich)
drawTable(tableSort)
})
}
html,
body {
height: 100%;
margin: 0;
}
.grid {
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.grid>div {
display: flex;
flex-basis: calc(100%/4 - 28px);
justify-content: center;
flex-direction: column;
padding: 10px;
}
.box {
margin: 0;
}
.box {
color: #000;
border: .5px solid #ccc;
}
.hrbox {
background-color: #333;
color: #fff;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
<div id="table">
<div class="grid">
<div class="box hrbox name">
<div>name</div>
</div>
<div class="box hrbox dept">
<div>dept</div>
</div>
<div class="box hrbox region">
<div>region</div>
</div>
<div class="box hrbox items">
<div>items</div>
</div>
</div>
<div id="data-table"></div>
</div>
</body>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
There are some problems here:
sort()
sorts the array in place, no need for thattableSort
variable- Removing the elements for painting the table again is not idiomatic D3, just use enter/update/exit selections.
Regarding your secondary question, if you had the proper variable names you could just use bracket notation, removing all that if...else
section:
data.sort((a, b) => d3.ascending(a[sortWhich], b[sortWhich]))