Reputation: 3789
I have a function to sort list items based on the date and class of the list item. It's late and I am tired and frustrated, so not sure what I am missing here.
The function should first determine if the class is .pinned
and sort them by date and insert them to the top of the list.
Then it should look at the date of the item (found in data-date) and if it is earlier than today, add the class .past
sort them by date, and then insert them after the pinned items.
Lastly, it should sort the remaining items and insert them after the last item with the class of .past
here is the code:
//sort todo list-items by type and then date
function sortTodo() {
var itemDate = "";
var date = new Date();
$(".todo-list-item").each(function() {
var itemDate = new Date($(this).data("date"));
if($(this).hasClass('pinned')) {
$(".todo-list-item.pinned").sort(function(a,b) {
return date > itemDate;
}).each(function() {
$(".todo-list").prepend(this);
})
} else if(date > itemDate) {
$(this).addClass("past");
$(".todo-list-item.past").sort(function(a,b) {
return date > itemDate;
}).each(function() {
$(".todo-list").prepend(this);
})
} else {
$(".todo-list-item").not(".pinned, .past").sort(function(a,b) {
return date > itemDate;
}).each(function() {
$(".todo-list").append(this);
})
}
});
}
$(document).ready(function() {
sortTodo();
});
as of now, the script not placing pinned items to the top as desired, unless I add a new pinned item, and is not sorting by date after an items class changes or is removed.
Upvotes: 1
Views: 494
Reputation: 338228
Your code is sorting and moving elements in three separate steps once per item (!). This messes up the order of the overall result.
Just sort once and append different sections of the sorted list one after another (jQuery .filter()
is useful for this). When you're through, all items will have been re-ordered.
Note about Array#sort
: It does not work when you return true
or false
. It expects you return numbers less than, equal to or greater than 0. Luckily, subtracting dates from one another gives you exactly these kinds of numbers.
The following sorts all items across all lists on the page.
// helper
function appendToParent() { this.parentNode.appendChild(this); }
$(function() {
var $items = $(".todo-list-item").sort(function(a, b) {
return new Date($(a).data("date")) - new Date($(b).data("date"));
});
// append items by priority
$items.filter(".pinned").each(appendToParent);
$items.filter(".pinned.past").each(appendToParent);
$items.filter(":not(.pinned)").each(appendToParent);
$items.filter(":not(.pinned).past").each(appendToParent);
});
.past { font-style: italic; }
.pinned { color: red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
List 1
<ul class="todo-list">
<li class="todo-list-item past" data-date="2017-05-03">Past Item 5</li>
<li class="todo-list-item" data-date="2017-06-04">Item 4</li>
<li class="todo-list-item pinned" data-date="2017-06-02">Item 1 (pinned)</li>
<li class="todo-list-item" data-date="2017-06-03">Item 3</li>
<li class="todo-list-item pinned past" data-date="2017-05-03">Past Item 2 (Pinned)</li>
</ul>
List 2
<ul class="todo-list">
<li class="todo-list-item past" data-date="2017-05-03">Past Item 5</li>
<li class="todo-list-item" data-date="2017-06-04">Item 4</li>
<li class="todo-list-item pinned" data-date="2017-06-02">Item 1 (pinned)</li>
<li class="todo-list-item" data-date="2017-06-03">Item 3</li>
<li class="todo-list-item pinned past" data-date="2017-05-03">Past Item 2 (Pinned)</li>
</ul>
Toggling the .past
class is easy, too, but I've left it out of the sample code above because at some point in the future all items here would end up being "past", which would defy the purpose of the sample code.
$items.each(function () {
$(this).toggleClass("past", new Date( $(this).data("date") ) < Date.now());
});
Upvotes: 1
Reputation: 184
The reason that the pinned item is not at the top of your list of todos on first page load is because it is the first item in your list to get prepended to the todo list.
When the page loads, the first item is pinned so it gets prepended to the list. Then it keeps looping through the list until it finds the items whose date > itemDate and puts it before the pinned item.
To see what I mean: try changing your html by putting the pinned item as the last item in your unordered list.
*Sorry - I don't have enough rep to leave a comment...
Upvotes: 1