Alphabet Search Reset Sorting along with Dropdowns
Alphabet Search Reset Sorting along with Dropdowns
Description of problem: I have a functioning alphabet sort, but I also have dropdown selections. I have a reset button that clears the search box and the drop downs, but I cannot figure out have to also make that same reset button reset the alphabet sort. I realize that the "All" button does this, but I need the other reset button to this as well because it isn't obvious when the user clicks reset that it has in fact reset when only one letter is still showing.
<script>var _alphabetSearch = '';
$.fn.dataTable.ext.search.push( function ( settings, searchData ) {
if ( ! _alphabetSearch ) {
return true;
}
if ( searchData[1].charAt(0) === _alphabetSearch ) {
return true;
}
return false;
} );
/* Formatting function for row details - modify as you need */
function format ( d ) {
// `d` is the original data object for the row
return '<div class="extra">'+
'<div class="row">'+
'<div class="col-md-9">'+d.description+'</div>'+
'<div class="col-md-3">'+'<a href="'+d.programurl+'" class="btn btn-default">'+'Visit Program Page'+'</a>'+'</div>'+
'</tr>'+
'</div>';
}
$(document).ready(function() {
var table = $('#program-list').DataTable(
{
"ajax": "programs.txt",
"columns": [
{
"className": 'details-control',
"orderable": false,
"data": null,
"defaultContent": '',
"render": function () {
return '<span class="fa fa-angle-down" aria-hidden="true"></span>';
},
},
{ "data": "program" },
{ "data": "school" },
{ "data": "type" },
{ "data": "location" }
],
"pageLength": 25,
"order": [[1, 'asc']],
"deferRender": true,
initComplete: function () {
this.api().column(2).every( function () {
var column = this;
var select = $('<select class="filter form-control mb-lg" id="school-filter"><option value="">School</option></select>')
.appendTo($("#college-filter"))
.on('change', function() {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search(val ? '^' + val + '$' : '', true, false)
.draw();
});
column.data().unique().sort().each(function(d, j) {
select.append('<option value="' + d + '">' + d + '</option>')
});
});
this.api().column(3).every( function () {
var column = this;
var select = $('<select class="filter form-control mb-lg" id="degree-type-filter"><option value="">Degree Type</option></select>')
.appendTo($("#degree-filter"))
.on('change', function() {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search(val ? '^' + val + '$' : '', true, false)
.draw();
});
column.data().unique().sort().each(function(d, j) {
select.append('<option value="' + d + '">' + d + '</option>')
});
});
this.api().column(4).every( function () {
var column = this;
var select = $('<select class="filter form-control mb-lg" id="location-type-filter"><option value="">Location</option></select>')
.appendTo($("#location-filter"))
.on('change', function() {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search(val ? '^' + val + '$' : '', true, false)
.draw();
});
column.data().unique().sort().each(function(d, j) {
select.append('<option value="' + d + '">' + d + '</option>')
});
})
}
}
);
var alphabet = $('<div class="alphabet"/>').append( '' );
$('<span class="clear active"/>')
.data( 'letter', '' )
.html( 'All' )
.appendTo( alphabet );
for ( var i=0 ; i<26 ; i++ ) {
var letter = String.fromCharCode( 65 + i );
$('<span/>')
.data( 'letter', letter )
.html( letter )
.appendTo( alphabet );
}
alphabet.insertBefore( table.table().container() );
alphabet.on( 'click', 'span', function () {
alphabet.find( '.active' ).removeClass( 'active' );
$(this).addClass( 'active' );
_alphabetSearch = $(this).data('letter');
table.draw();
} );
// Add event listener for opening and closing details
$('#program-list tbody').on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var tdi = tr.find(".fa");
var row = table.row( tr );
if ( row.child.isShown() ) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
tdi.first().removeClass('fa-angle-up');
tdi.first().addClass('fa-angle-down');
}
else {
// Open this row
row.child( format(row.data()) ).show();
tr.addClass('shown');
tdi.first().removeClass('fa-angle-down');
tdi.first().addClass('fa-angle-up');
}
});
$('[data-toggle="tooltip"]').tooltip();
if($('#school-filter').length == 0) {
$('#college-filter').append('<label for="school-filter" class="sr-only">School</label>');
}
$('[data-toggle="tooltip"]').tooltip();
if($('#degree-type-filter').length == 0) {
$('#degree-filter').append('<label for="degree-type-filter" class="sr-only">Degree Type</label>');
}
$('[data-toggle="tooltip"]').tooltip();
if($('#location-type-filter').length == 0) {
$('#location-filter').append('<label for="location-type-filter" class="sr-only">Location</label>');
}
$('#reset-filters').click(function (e) {
e.preventDefault();
var table = $('#program-list').DataTable();
console.log("reset table");
$('.filter').val("");
$('.filter').trigger('change');
table
.search('')
.columns().search('')
.draw();
});
});
</script>
<div class="program-list">
<div class="filters-container">
<div class="container">
<div class="row">
<div class="col-md-4 col-xl-4">
<div id="college-filter"></div>
</div>
<div class="col-md-4 col-xl-4">
<div id="degree-filter"></div>
</div>
<div class="col-md-4 col-xl-2">
<div id="location-filter"></div>
</div>
<div class="col-md-12 col-xl-2">
<button id="reset-filters">Reset <span class="fas fa-redo-alt"></span></button>
</div>
</div>
</div>
</div>
<div class="container p-0">
<div class="row no-gutters">
<div class="col">
<div class="table-responsive">
<table id="program-list" class="table">
<thead>
<tr>
<th scope="col"><span class="sr-only">Arrow Icons to Expand Sections</span></th>
<th scope="col" id="program">Program</th>
<th scope="col" id="school">School</th>
<th scope="col" id="type">Degree Type</th>
<th scope="col" id="location">Location</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</div>
Edited by Kevin: Update the markdown backticks to fix formatting.
This question has accepted answers - jump to:
Answers
This code:
Is setting your
All
button's 'letter' data attribute to an empty string.The click event:
Is getting the 'letter' data attribute, assigning it to the global variable
_alphabetSearch
and callingdraw()
which runs the search plugin used for the alphabet search. Basically you will need to clear theactive
class and set_alphabetSearch
to an empty string, for example add these line to your#reset-filters
click event:Kevin
Thank you so much! That worked like a charm.
If I wanted to create an array for an item in this same table, for instance, I wanted to add more than one location to an item, how would I get the dropdown for location to separate the two items? I know that I would need to change on line 38 my "data": "location" to "data": "location[, ]" and I would put each location inside a bracket in the .txt file, but the dropdown is still putting the two locations together. Is there something that would need to be done to lines 78-92 as well?
This code:
Is generating the select list.
d
is the value in the cell. You can change this to build the select lists the way you want. You may need an if statement to check the column index and if its thelocation
column use a different loop to build the select list otherwise use the one above.Kevin
Thank you Kevin, I thought that may be the case, but I am not familiar enough with arrays to be able to build it without an example. I've looked and looked, but haven't been able to find one. I was hoping there would be one on this site, but I just keep going in circles.
We're happy to take a look, but as per the forum rules, please link to a test case - a test case that replicates the issue will ensure you'll get a quick and accurate response. Information on how to create a test case (if you aren't able to link to the page you are working on) is available here.
Cheers,
Colin
I finally have a test case to share. You can see in the drop downs for core requirements and semesters that it is adding a comma between the array items, when I would like them to be listed as two separate entries.
I'm using a .txt file that you can find here: https://mse-dev.uark.edu/programs.txt
I've put the items in the .txt file that have multiple entries in brackets, which is working for displaying them inside the table, but not in the drop down filters above.
I also noticed that if I don't put anything in one of the arrays, it leaves a blank spot in the drop down as opposed to not adding anything at all.
I'm also wondering if filtering with some of these select inputs may be better as check boxes, but I haven't been able to find any examples of that on the datatable site.
https://mse-dev.uark.edu/
In your code,
you're adding all the data in that column. If you don't want black entries, just check for an empty string being adding to the
select
element.I'm not clear on this one, please can you give an example from your page.
There are a few threads here with checkbox searching, such as this example from this thread,
Colin
I'm getting close, here is another example. This time I added checkboxes to some of the items and it appears to be working, but my issue is that I would like the items under semester and core requirements drop downs to have one item each and separate out the items instead of combining them with commas. I just don't know enough about generating that type of JavaScript to know how to make that happen.
https://mse-dev.uark.edu/index-test.php
The issue will be similar to the one above, it'll be in the same code. There, it's adding the entire string into the
select
element. Instead, you'll want tosplit()
the string, and add each element into theselect
, something like:Colin
The split kind of worked. It did break the items into individual pieces, but now I have duplicates. I also still can't figure out how to check for empty items. It also appears when clicking on the items in the dropdown for the items that are split that it doesn't filter each one correctly. That may be because spaces are being added in front of the values of some items.
https://mse-dev.uark.edu/index-test.php
Just curious, would it be easier/or better to manually add the select filters at the top than pulling it dynamically? If so, what would that look like?
You can use Javascript trim() to remove leading and trailing spaces.
Use an array to keep track of what you have added to the select list to check against for duplicates.
Do you mean like the second option in your list? Just is an if statement.
Maybe something close to this will work:
Kevin
I tried that last suggestion, but I keep getting the error "options.include is not a function" You can see it here:
https://mse-dev.uark.edu/index.php
Sorry you need to use the Javascript array includes() method. Add an
s
tooptions.include( el)
in the above code snippet.Kevin
So that appeared to have done the trick with listing one item in the select list and removing the empty item, but when I click on Math it only shows one item, the one by itself, even though there are two and when I click on computer, it doesn't show the listing that has computer in it. I feel like it's so close, but the filtering isn't working 100% correctly.
https://mse-dev.uark.edu/index.php
You are using this search:
This is a regex search that would look something like this:
^Computer$
. This is looking for the start of the cell to haveC
and the end to haver
but your data looks like this:You can try removing the
^
and$
. You can try using smart search mode. See thesearch()
docs for details of the different modes.Kevin
I think removing the ^ and $ did the trick. I think it's finally working the way I hoped it would. You are a life saver. Thank you!!!!!
One more question, I'm having trouble getting just the core requirements select drop down to show in alphabetical order. I used the sort(function(a, b){return a-b}) method and in the semester drop down it changed the order except for SP8W1, and for some reason the core requirements has math at the top.
https://mse-dev.uark.edu/index.php
You're doing the sort on the full string, not when you've split them down to the individual components,
Colin
If that's true, then do I move the sort code sort(function(a, b){return a-b}) down inside the forEach function? I'm not sure how to add that sort after they've been split.
column.data().unique().sort(function(a, b){return a-b}).each(function(d, j) {
d.split(',').forEach(function(el) {
el = el.trim();
if ( el !== '' && ! options.includes(el) ) {
options.push(el);
select.append('<option value="' + el + '">' + el + '</option>')
}
The easiest way is to build the select options in a couple steps. The first step is to start with an empty array and loop through the column data and split the text - the order doesn't matter. Loop through the slit text result and push only those values that don't exist onto the array.
Now you have an array of all the unique split text values. Loop through the sorted list and build your select options.
Kevin
I found this article that helped me.
https://stackoverflow.com/questions/67791400/how-to-apply-ascending-sort-to-split-data-in-datatable
I think I'm good now.