Isotope filtering using checkboxes issue - javascript

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.

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>

How to hide or show divs based on checkbox change event

I am trying to show the values based on Checkbox check and uncheck
I have got two checkboxes MNC and Worth (Only the Top Ones), i am trying to show or hide the values based on it (pesent under class pack-panel div)
This is my code
$(document).on('change', '.filtermnc', function() {
$(".pack-panel").each(function () {
var visible = $(this).find('.mnccheckbox').prop('checked')
$(this).toggle(visible);
});
});
$(document).on('change', '.filterworth', function() {
$(".pack-panel").each(function () {
var visible = $(this).find('.worthcheckbox').prop('checked')
$(this).toggle(visible);
});
});
When i tried with this code , it is not working and also it is checking all the correspondng checkboxes
Could you please let me know how to achieve this .
http://jsfiddle.net/F8Vk2/121/
I made for one, but it's just a mater of changing the other one likewise:
$(document).on('change', '.filterworth, .filtermnc', function() {
var $this = $(this),
isChecked = $this.is(':checked'),
$packPanel = $('.pack-panel');
isChecked ? $packPanel.show() : $packPanel.hide()
});
You could use this to get the target of the event and verify if it's checked by .is(':checked'). Also, you don't need to iterate over $('.pack-panel') in order to apply your changes. .toggle() will change the visibility by it's previous one, so I think you should hard code to hide or show the panels.
Change your js to
$(document).on('change', '.filtermnc', function() {
var visible = $(this).prop('checked')
if(visible)
$('.mnccheckbox').closest("li").show();
else
$('.mnccheckbox').closest("li").hide();
});
$(document).on('change', '.filterworth', function() {
var visible = $(this).prop('checked')
if(visible)
$('.worthcheckbox').closest("li").show();
else
$('.worthcheckbox').closest("li").hide();
});
http://jsfiddle.net/F8Vk2/123/
You could try ->
$(document).on('change', '.filtermnc', function() {
$('.mnccheckbox').
closest("li").
toggle($(this).prop('checked'));
});
This is basically finding all with .mccheckbox class, and then toggling based on the property of the checkbox you assigned the event too.

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.

jQuery Isotope filter to no items?

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;

Categories

Resources