jQuery Isotope filter to no items? - javascript

I'm using isotope to filter a list with multiple filters where it is possible that based on a combination of certain filters no items will be displayed. In this case I want to display a message to the user that based on their filter parameters, no results exist. How would I go about that and does isotope have something built in to handle this? Here is a jsfiddle example. should be displayed if no items match filter set...
http://jsfiddle.net/cssguru/e4vA3/
$(function(){
var $container = $('#container'),
$checkboxes = $('#filters input');
$container.isotope({
itemSelector: '.item'
});
$checkboxes.change(function(){
var filters = [];
// get checked checkboxes values
$checkboxes.filter(':checked').each(function(){
filters.push( this.value );
});
// ['.red', '.blue'] -> '.red, .blue'
filters = filters.join('');
$container.isotope({ filter: filters });
});
});

You can could to see how many isotope items do not have the "isotope-hidden" class added to it. When the result is 0, it means that all of your elements will be hidden and you can trigger something to happen. You could use a callback function, like reLayout to run every time the isotope gets filtered.
function noResultsCheck() {
var numItems = $('.item:not(.isotope-hidden)').length;
if (numItems == 0) {
//do something here, like turn on a div, or insert a msg with jQuery's .html() function
alert("There are no results");
}
}
Add this to your change function:
$container.isotope( 'reLayout', noResultsCheck );
http://jsfiddle.net/xvU8D/

Just to add to what nspace said...
You don't need to add the 'reLayout' callback, you can make the callback in the code you already had here $container.isotope({ filter: filters }); like this:
$container.isotope({ filter: filters }, function noResultsCheck() {
var numItems = $('.item:not(.isotope-hidden)').length;
if (numItems == 0) {
alert("There are no results");
}
});
http://jsfiddle.net/xvU8D/33/
This is taken from the docs here:
http://isotope.metafizzy.co/docs/introduction.html#script - do a page search for 'callback'.

Just found a great solution at isotopes github issue-page.
Isotope v1:
$container.isotope({ filter: '.my-crazy.awesome.filter' });
if ( !$container.data('isotope').$filteredAtoms.length == 0) {
// do stuff when no element was found
}
See Isotope Help - accessing the instance
Isotope v2
if ( !$container.data('isotope').filteredItems.length == 0) {
// do stuff when no element was found
}
See Isotope - Filtered Items
see full post here

In addition, to work in Isotope 2 you have to check if it is visible/not visible instead of having the class isotope-hidden:
Like this
var numItems = $('.item:visible').length;

Related

Isotope v2 Grid - Multiple Filters - Hide empty filters

My current isotope grid has two dropdown filters that sort the grid items. The first filter is menu type, and the second filter is drink type. Each menu type however does not contain all drink types so when some filter configurations are chosen, no results are showed, which is correct. But i would like to stop this from happening by when the user selects the first filter, the second filter hides the empty types.
Working Codepen of current filters: https://codepen.io/whitinggg/pen/zYGEaNb
This was my old filter code:
// Select Filters
jQuery(function ($) {
var $grid = $('.grid');
var $selects = $('div#filterGroup select').change(function() {
var selector = $selects.get().map(function(el) { // map the select elements ...
return $(el).val(); // ... to an array of values
}).join('') || '*'; // if joined array is empty-string, then default to a single '*'
$grid.isotope({
'filter': selector
});
return false;
});
$grid.imagesLoaded().progress( function() {
$grid.isotope('layout');
});
});
I have tried to change my code to the below from other links around the internet on this topic but havent had any luck getting it to work.
// Select Filters
jQuery(function ($) {
var $grid = $('.grid');
var $selects = $('div#filterGroup select').change(function() {
var selector = $selects.get().map(function(el) { // map the select elements ...
return $(el).val(); // ... to an array of values
}).join('') || '*'; // if joined array is empty-string, then default to a single '*'
$grid.isotope({
'filter': selector
});
return false;
});
//Hide Empty Filters
var DROP = $('div#filterGroup select option:not([data-filter=""])');
// list of all class in html
var strall = ''; $('.grid-item').each(function(el){ strall += $(this).attr('class') });
// remove select if not in strall.. TODO : needs improvement, this is kind a hack
DROP.each(function(el){
var nowfilter = $(this).attr('data-filter').replace('.', ''); // co_kenya
if( strall.indexOf( nowfilter ) == -1 ){
console.log( 'this one is missing ' + nowfilter );
$(this).remove();
}
});
$grid.imagesLoaded().progress( function() {
$grid.isotope('layout');
});
});
Is this possible? Any help much appreciated!
Working codepen
First, add an ID to each drop-down so that we can distinguish them.
<select id="menu-selector" class="filter option-set" data-filter-group="menu">
[...]
<select id="type-selector" class="filter option-set" data-filter-group="categories">
Then, for each drop-down, add a change listener. We'll look at the code for the menu drop-down change listener.
First, get the class filter from the selected drop-down:
$('#menu-selector').change(function() {
var selectedClass = $('#menu-selector option:selected').attr('value');
Then we're going to select all of the grid items matching that type, to see what other classes they have. These other classes will be the available types
var availableTypes = $(`.grid-item${selectedClass}`)
.toArray()
.flatMap(div => Array.from(div.classList.values())) //get all of the classes
.filter(i => !['grid-item', selectedClass.substring(1)].includes(i)); //eliminate useless ones
Last, toggle the disabled property on the other drop-down, enabling only those that are available.
$('#type-selector option')
.each( (i,el) => $(el).prop('disabled', el.value != "" && !availableTypes.includes(el.value.substring(1))));
That should do it. The change handler for the type drop-down is the same but references the opposite drop-down. Check the codepen for details.

Isotope combination filter display, I want to split the text array into divs

I have a page using isotope filter plugin. The filter is triggered by checkbox. The filtering works, and the filter count works. I want to print what filter is applied and also be able to "uncheck" the filter checkbox if I click the printed filter value. The $filterdisplay is working, but its a string seperated by commas. I want to split the string into clickable divs that would unfilter the filter selected.
I tried splitting the array into divs but it caused the printed value to fire more than once. If c0 is checked and then after c1 is checked it would show:
<div>c0</div><div>c0</div><div>c1</div>
This example is pretty close to what I want except its not using checkboxes:
http://everyonelovessharing.com/misc/isotopedemo/
$(function(){
var $container = $('#grid'),
$checkboxes = $('#filters input');
var $filterCount = $('.filter-count');
var iso = $container.data('isotope');
var $filterDisplay = $('#filter-display');
$checkboxes.change(function(){
var filters = [];
// get checked checkboxes values
$checkboxes.filter(':checked').each(function(){
filters.push( this.value);
});
// ['.red', '.blue'] -> '.red, .blue'
filters = filters.join(', ');
$container.isotope({ filter: filters });
updateFilterCount();
// this made the checkboxes show up multiple times in the display
// filters.split(', ').map(function(opt) {
// $("<div>").text(opt).appendTo( $filterDisplay );
// });
$filterDisplay.text( filters );
});
function updateFilterCount() {
$filterCount.text( iso.filteredItems.length + ' webinars match selected filters.' );
}
updateFilterCount();
//Reset btn
$(".filter-reset").click(function () {
$container.isotope({
filter: '*'
});
updateFilterCount();
$('#filters input:checkbox').prop('checked', false);
$filterDisplay.text( '' );
filters = {};
console.log(filters);
});
});
</script>

Isotope filtering using checkboxes issue

I'm trying to make filtering Isotope to work out but I'm stuck.
I have two lists of checkbox filters in which every list there is a clear-list button, in order to uncheck the checkboxes in their list and one clear-all button that unchecks all the checkboxes and does isotope({filter: '*' }) when clicked, which is desired.
My problem is that I cannot figure out how to make the clear-list button to isotope the grid container when a clearlist button is clicked.
Logically, the grid container must isotope without the values of the certain list.
And when all lists are clear with the clear-list button then the grid should isotope({ filter: '*' })
Here is my js code
function initIsotope(){
var $wrapper = $('.wrapper');
if($wrapper.length < 1){
return;
}
var $filters = $('.filters', $wrapper);
var $grid = $('.grid-container', $wrapper);
var $checkboxList = $ ('.checkbox-list', $wrapper);
var $checkboxes = $('.checkbox-control', $wrapper);
var $clearList = $('.clear-list', $wrapper);
var $clearAll= $('.clear-all', $wrapper);
//init Isotope
$grid.isotope({
itemSelector: '.grid-item',
layoutMode: 'fitRows'
});
//isotope filtering on checkbox click
// this part of code is from http://jsfiddle.net/desandro/DQydj/
$checkboxes.change(function(){
var filters = [];
// get checked checkboxes values
$checkboxes.filter(':checked').each(function(){
filters.push( this.value );
});
filters = filters.join(', ');
$grid.isotope({ filter: filters });
});
//clear list
$clearList.on('click', function(e){
e.preventDefault();
var $self = $(this);
$self.closest($checkboxList).find($checkboxes).prop("checked", false);
//Im stuck here
});
//clear-all lists
$clearAll.on('click',function(e){
e.preventDefault();
$checkboxes.prop("checked", false);
$grid.isotope({ filter: '*' });
});
}
$(function(){
initIsotope();
});
Have jsfiddle example for you to see:
https://jsfiddle.net/timosergio/at7gtc1g/35/
Can you help me out please?
PS: I've updated my jsFiddle, I'm closer but to the desire result. Check it out if you mind
The only thing missing in your $clearList.on('click'), after having the correct closest($checkboxList) cleared is to "reset" the filter array... And "repopulate" it with the possible values of the other checkbox-list.
// Empty filter array
var filters = [];
// get checked checkboxes values
$checkboxes.filter(':checked').each(function(){
filters.push( this.value );
});
filters = filters.join(', ');
$grid.isotope({ filter: filters });
Like you do in the function $checkboxes.change...
You send a value array to grid.isotope to use as filter.
You already do the right thing in $clearAll.on('click')
You are sending '*'.
EDIT
I just updated my fiddle to simplify the script by avoiding redundant code.
I made a "sub-function" with the part that gets the checkboxes values.
;)
Updated Fiddle
NOTE to other SO readers: "isotope" is a cool js library.

Change event firing without click

I am currently using the isotope plugin to create a function that allows me to place multiple select dropdowns. When the user has selected the dropdowns and when they click submit, it fires the event and rearranges the items.
The problem i am recieving is that the change event is firing and removing everything, but when i click submit, the right results are returned.
Jquery:
jQuery(document).ready(function($) {
var $container = $('.finalblock'),
filters = {},
selector;
$container.isotope({
itemSelector : '.finalchannel',
layoutMode: 'none'
});
$('select').change(function(){
var $this = $(this);
$('#mainSubmission').click(function() {
var group = $this.attr('data-filter-group');
filters[ group ] = $this.find(':selected').attr('data-filter-value');
var isoFilters = [];
for ( var prop in filters ) {
isoFilters.push( filters[ prop ] )
}
var selector = isoFilters.join('');
$container.isotope({ filter: selector });
return false;
});
});
});
Iv been looking into the bind() function but that doesnt seem to be giving me the right thing (maybe cause i must be doing something wrong.
$('select').bind('initCheckboxes change', function() {
// do some stuff including ajax work
}).trigger('initCheckboxes');
EDIT:
JSFIDDLE: http://jsfiddle.net/Lnzkv3v7/
Just looking at your code, (on the website itself, not the jsfiddle):
The first select element has the id of filters
<select id="filters" data-filter-group="mainfilter">
but did you know that was stored as a variable in your js?
var $container = $('.finalblock'),
filters = {},
selector;
Since most of these elements are being pulled in by Isotope anyways, this could be the issue. The reason why this is a theory is because your second select element doesnt seem to be causing an issue. So change the first select id to something else and see if it works.

Using JQuery detach and restore to filter a select list

http://jsfiddle.net/Ms9NY/
I'm using jquery and trying to use detach/prepend/append to dynamically remove and reinsert option items on a select.
Because hiding options does not work cross browser, the only way to really get it to function as needed is removing the options completely.
I can remove the items with detach but I'm lost on how to restore them later. I know I would need to add them to an array somehow but I can't figure out how to do that. How can I use an array to detach and restore only specifically matched items from the deleted list?
This is what I have been testing with:
$("#filter-specs-text").keyup(function(){
var searchString = $(this).val().toLowerCase();
$("#specs-excluded-select>option").each(function() {
var text = $(this).text().toLowerCase();
//found a match - show this entry
if ( text.indexOf(searchString) > -1 ) {
$(this).removeAttr("disabled");
$(this).prependTo("#specs-excluded-select");
}
//no match - hide this entry
else {
$(this).attr("disabled", "disabled");
$(this).detach();
}
});
Visual reference. The filter box is the text box noted by the arrow.
You could handle it like this instead:
--DEMO--
var $opts = $("#specs-excluded-select>option"); // keeping there all options
$("#filter-specs-text").keyup(function () {
var searchString = $(this).val().toLowerCase();
$("#specs-excluded-select").empty().append($opts); // append() to keep any data/events bound to options
$("#specs-excluded-select>option").each(function () {
var text = $(this).text().toLowerCase();
//found a match - show this entry
if (text.indexOf(searchString) > -1) {
$(this).prop("disabled", false);
}
//no match - hide this entry
else {
$(this).prop("disabled", true).detach();
}
});
});

Categories

Resources