Skip to content

Instantly share code, notes, and snippets.

@AJLeonardi
Last active September 2, 2022 16:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AJLeonardi/ca56c8ae1a67e14c24357a92e07877b2 to your computer and use it in GitHub Desktop.
Save AJLeonardi/ca56c8ae1a67e14c24357a92e07877b2 to your computer and use it in GitHub Desktop.
A Javascript class that sorts Grids by clicking on the column header. Specifically this one was created to sort grids created using MaterializeCSS Collections. Sorting supports strings, numbers, and dates and will sort ascending and descending. Demo here: https://jsfiddle.net/AJLeonardi/etjwq7uc/
/*
Supports grids created with ordered and unordered lists. Specifically this was created to support sorting
1. In your ul, include a list of dictionaries in this format - representing the sortable items: [{"name": "<key name of your column e.g. 'Date_of_Birth'>", "data_type": "<number, string, or date>"}, ....]
2. Within the li containing your column headers, each html element representing the header of a sortable column should have a "data-header" attribute which is set to the corresponding "name" <div class="column" data-header="Date_of_Birth">
3. Within each subsequent li, the li should contain a data attribute for each sortable item's value in this format: <li class='item' data-Date_of_Birth='10/10/2001'>
4. make a ul sortable by instantiating with: new SortedGrid(ul_obj, "<the column 'name' that is sorted by default>", "<the name of your ascending sort css class for your column header>", "<the name of your ascending sort css class for your column header>");
Full working demo here: https://jsfiddle.net/AJLeonardi/etjwq7uc/
Example:
<ul id='test' data-sortable_fields='[{"name": "name", "data_type": "string"}, {"name":"score_1","data_type":"number"}, {"name":"date","data_type":"date"}]' class="collection">
<li class="collection-item">
<div class="row valign-wrapper">
<div class="col s2 strong" data-header="name">Name</div>
<div class="col s2 strong" data-header="score_1">Score 1</div>
<div class="col s2 strong"data-header="date">Date</div>
</div>
</li>
<li class="collection-item" data-name="Anthony" data-score_1=20.1 data-date="06/30/2016">
<div class="row valign-wrapper">
<div class="col s2">Anthony</div>
<div class="col s2">20.1</div>
<div class="col s2">06/30/2016</div>
</div>
</li>
<li class="collection-item" data-name="Jacob" data-score_1=20.2 data-date="10/15/2016">
<div class="row valign-wrapper">
<div class="col s2">Jacob</div>
<div class="col s2">20.2</div>
<div class="col s2">10/15/2016</div>
</div>
</li>
<li class="collection-item" data-name="Brian" data-score_1=22 data-date="04/20/2011">
<div class="row valign-wrapper">
<div class="col s2">Brian</div>
<div class="col s2">22</div>
<div class="col s2">04/20/2011</div>
</div>
</li>
</ul>
<script>
const ul_obj = document.getElementById('test');
var test_sort = new SortedGrid(ul_obj, "name", "sorted-column-asc", "sorted-column-desc");
</script>
*/
class SortedGrid {
constructor(ul_element, default_sort_type, sorted_column_asc_css_class, sorted_column_desc_css_class) {
const instance = this;
this.ul_element = ul_element;
this.sort_type_list = JSON.parse(ul_element.dataset.sortable_fields);
this.li_list = ul_element.querySelectorAll('li');
this.li_headers = null;
this.sorted_column_asc_css_class = sorted_column_asc_css_class;
this.sorted_column_desc_css_class = sorted_column_desc_css_class;
this.sort_state = instance.constructSortState(this.sort_type_list, default_sort_type);
for (var x = 0; x < this.sort_type_list.length; x++) {
var curr_sort_type = this.sort_type_list[x].name;
for (var i = 0; i < this.li_list.length; i++) {
var li_item = this.li_list[i]
var sort_thing_val = li_item.dataset[curr_sort_type];
if (typeof sort_thing_val == 'undefined') {
this.li_headers = li_item.querySelectorAll('[data-header]');
for (var n = 0; n < this.li_headers.length; n++) {
var header_element = this.li_headers[n];
var header_type = header_element.dataset.header;
if (header_type == curr_sort_type) {
header_element.addEventListener("mouseup", function (e) {
var header = e.target.dataset.header
instance.sortList(header);
});
}
}
}
}
}
this.updateHeaders();
}
constructSortState(sort_type_list, default_sort_type) {
var sts = {};
for (var i = 0; i < sort_type_list.length; i++) {
var sort_type = sort_type_list[i];
if (sort_type.name == default_sort_type){
var is_ascending = true;
var is_default = true;
}
else{
var is_ascending = null;
var is_default = false;
}
sts[sort_type.name] = {
"is_ascending": is_ascending,
"is_default": is_default,
"type": sort_type.data_type
}
}
return sts;
}
sortList(sort_by) {
var is_ascending = this.sort_state[sort_by].is_ascending;
if (is_ascending == null || is_ascending == false) {
//this.sortAscending(sort_by);
this.doSort(sort_by, 1);
} else {
//this.sortDescending(sort_by);
this.doSort(sort_by, -1);
}
this.updateHeaders();
}
doSort(sort_by, order_modifier) {
const sortList = list => [...list].sort((a, b) => {
const first = a.dataset[sort_by];
const second = b.dataset[sort_by];
if (first == undefined){
return -1;
}
else if (second == undefined){
return 1;
}
else {
if (this.sort_state[sort_by].type == "number"){
var A = Number(first), B = Number(second);
}
else if (this.sort_state[sort_by].type == "string"){
var A = String(first).toLowerCase(), B = String(second).toLowerCase();
}
else if (this.sort_state[sort_by].type == "date"){
var A = new Date(first).getTime(), B = new Date(second).getTime();
}
return (A < B) ? (-1 * order_modifier) : (A > B) ? (1 * order_modifier) : 0;
}
});
this.ul_element.append(...sortList(this.li_list));
this.updateSortState(sort_by, (order_modifier == 1));
}
updateSortState(sort_by, state) {
for (var i = 0; i < this.sort_type_list.length; i++) {
var sort_type = this.sort_type_list[i].name;
if (sort_type == sort_by) {
this.sort_state[sort_type].is_ascending = state;
} else {
this.sort_state[sort_type].is_ascending = null;
}
}
}
updateHeaders(){
for (var i=0; i<this.li_headers.length; i++){
var header = this.li_headers[i];
var header_type = header.dataset.header;
if (this.sort_state[header_type].is_ascending == true){
header.classList.add(this.sorted_column_asc_css_class);
header.classList.remove(this.sorted_column_desc_css_class);
}
else if (this.sort_state[header_type].is_ascending == false){
header.classList.add(this.sorted_column_desc_css_class);
header.classList.remove(this.sorted_column_asc_css_class);
}
else{
header.classList.remove(this.sorted_column_asc_css_class);
header.classList.remove(this.sorted_column_desc_css_class);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment