I have a function that sorts courses (divs) based on an end date that is declared in a data attribute. The entire list of classes is sorting correct except one. I cannot figure out why it is not sorting it correctly. The March 24th is the first one in the sorted list.
I am guessing it is only looking at the "2" in "24" but I am not sure how to get around this, if it is the case.
HTML
<button onClick="courseSort()">SORT</button>
<div id="course-container" >
<div data-class-start="1/1/2022" data-class-end="5/28/2022">
<h5>May 28</h5>
</div>
<div data-class-start="2/8/2022" data-class-end="3/9/2022">
<h5>Mar 9</h5>
</div>
<div data-class-start="1/1/2022" data-class-end="3/5/2022">
<h5>Mar 5</h5>
</div>
<div data-class-start="1/1/2022" data-class-end="4/1/2022">
<h5>Apr 1</h5>
</div>
<div data-class-start="2/19/2022" data-class-end="3/8/2022">
<h5>Mar 8</h5>
</div>
<div data-class-start="2/19/2022" data-class-end="3/24/2022">
<h5>Mar 24</h5>
</div>
<div data-class-start="1/1/2022" data-class-end="4/23/2022">
<h5>Apr 23</h5>
</div>
<div data-class-start="1/1/2022" data-class-end="4/30/2022">
<h5>Apr 30</h5>
</div>
</div>
JS
function sorter(a, b) {
if (a.dataset.classEnd < b.dataset.classEnd)
return -1;
if (a.dataset.classEnd > b.dataset.classEnd)
return 1;
return 0;
}
// Function to sort Data
function courseSort() {
var course = document.querySelectorAll("[data-class-end]");
var courseArray = Array.from(course);
let sorted = courseArray.sort(sorter);
sorted.forEach(e =>
document.querySelector("#course-container").appendChild(e));
}
Thanks
CodePudding user response:
Check function sorter(a, b)
. When you're accessing for example a.dataset.classEnd
, it's a string, not a date. You may want to do something like:
function sorter(a, b) {
const [aDate, bDate] = [new Date(a.dataset.classEnd), new Date(b.dataset.classEnd)];
if (aDate < bDate) return -1;
if (aDate > bDate) return 1;
return 0;
}
Also, you could simply do this like a one-liner instead of a separated function:
let sorted = courseArray.sort((a, b) => new Date(a.dataset.classEnd) - new Date(b.dataset.classEnd));
I am guessing it is only looking at the "2" in "24" but I am not sure how to get around this, if it is the case.
Yes, that's exactly what was happening as you were comparing strings.
EDIT: As Sebastian Simon suggested in comments, you may like to change the format of your dates to allow sorting without really needing to convert the variables to date.
CodePudding user response:
As already mentioned in comments, the true value of a date can be derived from the Date object. In the example below, the function courseArray(nodeList)
will:
- convert the NodeList into an array run it through
.map()
[...nodeList].map(d => {... // [...nodeList] is the same as Array.from(nodeList)
- extract the value from
data-class-end
and convert it to ISO formatlet mmddyyyy = d.dataset.classEnd; let yyyymmdd = mmddyyyy.split('/'); let yyyy = yyyymmdd.pop(); yyyymmdd.unshift(yyyy); let ISO = yyyymmdd.join('-'); // from mm/dd/yyyy to yyyy-mm-dd
- then it is converted to the number of milli-seconds since 1-1-1970 to the ISO date -- then it's added as
data-order
to the div and then the divs are reordered according todata-order
value.let ms = Date.parse(ISO); d.dataset.order = ms; return d; }).sort((a, b) => a.dataset.order - b.dataset.order);
Also, the inline event handler was removed and a onevent property event handler was added. See why inline event handlers are garbage.
const courseArray = nodeList => {
return [...nodeList].map(d => {
let mmddyyyy = d.dataset.classEnd;
let yyyymmdd = mmddyyyy.split('/');
let yyyy = yyyymmdd.pop();
yyyymmdd.unshift(yyyy);
let ISO = yyyymmdd.join('-');
let ms = Date.parse(ISO);
d.dataset.order = ms;
return d;
}).sort((a, b) => a.dataset.order - b.dataset.order);
};
function courseSort() {
const course = document.querySelectorAll(".class-item");
let sorted = courseArray(course);
sorted.forEach(e =>
document.querySelector("#course-container").appendChild(e));
};
document.querySelector('button').onclick = courseSort;
<button>SORT</button>
<div id="course-container" >
<div data-class-start="1/1/2022" data-class-end="5/28/2022">
<h5>May 28</h5>
</div>
<div data-class-start="2/8/2022" data-class-end="3/9/2022">
<h5>Mar 9</h5>
</div>
<div data-class-start="1/1/2022" data-class-end="3/5/2022">
<h5>Mar 5</h5>
</div>
<div data-class-start="1/1/2022" data-class-end="4/1/2022">
<h5>Apr 1</h5>
</div>
<div data-class-start="2/19/2022" data-class-end="3/8/2022">
<h5>Mar 8</h5>
</div>
<div data-class-start="2/19/2022" data-class-end="3/24/2022">
<h5>Mar 24</h5>
</div>
<div data-class-start="1/1/2022" data-class-end="4/23/2022">
<h5>Apr 23</h5>
</div>
<div data-class-start="1/1/2022" data-class-end="4/30/2022">
<h5>Apr 30</h5>
</div>
</div>