Filter DIVs with cards inside - javascript

I need to filter DIVs with cards inside by their categories.
In my issue it works only with letters. I think problem is in Javascript, but I cant see it.
Do you know what it is?
I created 5 buttons with exact categories 'a', 'b' 'c' etc.
If I want to show only category 'A', I'll use data-cat="a" in div.
If inside div is only one letter, it work fine, but If I put div with cards and images inside and tag them as data-cat="a", their visibility is changing to "none". So, if I press button to filter category A I can see only letters without a card inside it. If you don't understand what I mean try Live Preview: http://filter.8u.cz
I want to see shopping card when I click on exact category.
<!--This one works-->
<div class="portfolio-item" data-cat="a">A</div>
If I put another div with card inside, it's not visible.
var Portfolio = {
sort: function (items) {
Portfolio.hideAll($('#portfolio-content *'));
Portfolio.showAll(items);
},
showAll: function (items) {
items.fadeIn(700);
},
hideAll: function (items) {
items.hide();
},
doSort: function () {
$('div', '.button-group').on('click', function () {
var $a = $(this);
if (!$a.is('#all')) {
var items = $('div[data-cat=' + $a.data('cat') + ']', '#portfolio-content');
Portfolio.sort(items);
} else {
var items = $('#portfolio-content *');
Portfolio.hideAll(items);
Portfolio.showAll(items);
}
});
}
};
Portfolio.doSort();

Change $("#portfolio-content *") to $("#portfolio-content .portfolio-item").
With *, you are referencing EVERY child element, no matter if it is an image, span or anything else.
By referencing .portfolio-item, you will only hide the wrappers, instead of hiding its children.

Related

I have a list of buttons with the same class name but different inner text, how do I get the value of the text on click?

My list is being populated with this block of code:
function addToHistory(cityName) {
let searchHistory = JSON.parse(localStorage.getItem("Weather Search History")) || [];
searchHistory.push(cityName);
localStorage.setItem("Weather Search History", JSON.stringify(searchHistory));
};
function updateHistory() {
let searchHistory = JSON.parse(localStorage.getItem("Weather Search History")) || [];
$("#searchHistory").html(searchHistory
.map(searchHistoryList => {
return (`<li><button class="btn btn-link"> ` + searchHistoryList + `</button></li>`);
})
.join(""));
};
and that works great. It pulls from an array in local storage that is created each time the user enters a search term. Then populates the site's sidebar with said list.
However, I'm not sure how to then take the text values of the buttons out so that I may manipulate it.
Currently have:
$('#searchHistory').on('click', function () {
console.log($(???).val());
});
You want .text() or innerText (plain JavaScript). this refers to the current element. You can also use event.target.
$('#searchHistory').on('click', function () {
console.log($(this).text());
});
Try this in your function:
console.log($(this).innerHTML());
"this" refers to the specific element that triggered the click event.

Checkboxes that display results with jQuery

I am trying to have the user check the boxes they are interested in getting resources for and then click the button to get a list of those resources that are hyperlinked to those resources. The hyperlinks (ul id="results” in HTML) are hidden until they called upon by the button “Get Resources”.
Plus I would like to add text to it before results saying “You have indicated an interest in:” (line break) then a listing the hyperlinks (line break) “Please click on the links to learn more”. If no check box is selected the div id=“alert” displays, which I got to work.
I think I am very close, I just can’t seem to get the list of resources.
Here is a link to my coding:
JSFiddle Code sample
$(document).ready(function() {
$('#alert').hide();
$('#results > li').hide();
/* Get the checkboxes values based on the parent div id */
$("#resourcesButton").click(function() {
getValue();
});
});
function getValue(){
var chkArray = [];
/* look for all checkboxes that have a parent id called 'checkboxlist' attached to it and check if it was checked */
$("#checkBoxes input:checked").each(function() {
chkArray.push($(this).val());
});
/* we join the array separated by the comma */
var selected;
selected = chkArray.join(',') + ",";
/* check if there is selected checkboxes, by default the length is 1 as it contains one single comma */
if(selected.length > 1){
// Would like it to say something before and after what is displayed
$('#results > li.' + $(this).attr('value')).show();
} else {
$('#alert').show();
}
}
I'd ditch the selected variable and just check the chkArray contents against the list item classes like:
function getValue() {
var chkArray = [];
/* look for all checkboxes that have a parent id called 'checkboxlist' attached to it and check if it was checked */
$("#checkBoxes input:checked").each(function () {
chkArray.push($(this).val());
});
$('#results li').each(function () {
if ($.inArray($(this).attr('class'), chkArray) > -1) $(this).show()
else($(this).hide())
})
/* check if there is selected checkboxes, by default the length is 1 as it contains one single comma */
if (!chkArray.length) {
$('#alert').show();
//alert("Please at least one of the checkbox");
}
}
jsFiddle example
I found a straightforward way of achieving what you want. DEMO: https://jsfiddle.net/erkaner/oagc50gy/8/
Here is my approach: I looped through all checkboxes. This way I could get the index of the current item in the original list, i, and use this index to display the corresponding item in the second list. I filter the checked items by using .is(':checked') condition, and then added them item to the array:
function getValue() {
var chkArray = [];
$("#checkBoxes input").each(function (i) {//now we can get the original index anytime
if($(this).is(':checked')){//is the item checked?
chkArray.push($(this).val());//if so add it to the array
var selected;
selected = chkArray.join(", ");
if (selected.length) {
$('#results').find('li').eq(i).show();//show the corresponding link by using `i`
} else {
$('#alert').show();
}
}
});
}
Last thing in your $(document).ready function, add:
$("#checkBoxes input:checkbox").click(function() {
$('li.' + $(this).val().replace(/ /g, '.')).show()
});
JSFiddle
Explanation:
On document ready, add a click handler to the checkboxes that shows the corresponding hidden list item below. The tricky thing here is the spaces in the list names. This makes each word a separate classname, so simply combine the list names with a dot . which results in a sequential classname call in jQuery.
By using <li class="Fitness & Recreation"> as a list item classname, you are giving this item 3 classnames: Fitness, &, and Recreation. In jQuery you select elements with multiple classnames by including each name preceded by a dot .. For example, selecting a list item element with the classnames foo, bar, and baz:
$('li.foo.bar.baz').show()
In the case of <li class="Fitness & Recreation">:
$('li.Fitness.&.Recreation').show()
Since these values are stored in the value attribute of the checkboxes we use jQuery to pull these values: $(this).val(), replace the spaces with dots: .replace(/ /g, '.'), and concatenate the result to the li. portion to access the appropriate list item.

Modify function to filter by several data-attributes simultaneously

The function below allows users to filter products by data-attributes, and accommodates filtering by multiple values simultaneously. It does this by creating an array of the values selected, and when any of the values are clicked (in this case checked/unchecked) it hides all the items and then re-shows those that match the values in the updated array.
It works correctly when filtering for one data-attribute, but when combined to filter by more than one attribute it no longer shows all results matching any of the values and instead only shows results matching all the specified values.
I've posted a fiddle which demonstrates the problem here: http://jsfiddle.net/chayacooper/WZpMh/94/ All but one of the items have the values of both data-style="V-Neck" and data-color="Black" and they should therefore remain visible if either of the filters are selected, but if another value from a different data-attribute some of the items are hidden.
$(document).ready(function () {
var selected = [];
$('#attributes-Colors *').click(function () {
var attrColor = $(this).data('color');
var $this = $(this);
if ($this.parent().hasClass("active")) {
$this.parent().removeClass("active");
selected.splice(selected.indexOf(attrColor),1);
}
else {
$this.parent().addClass("active");
selected.push(attrColor);
}
$("#content").find("*").hide();
$.each(selected, function(index,item) {
$('#content').find('[data-color *="' + item + '"]').show();
});
return false;
});
$('#attributes-Silhouettes *').click(function () {
var attrStyle = $(this).data('style');
var $this = $(this);
if ($this.parent().hasClass("active")) {
$this.parent().removeClass("active");
selected.splice(selected.indexOf(attrStyle),1);
}
else {
$this.parent().addClass("active");
selected.push(attrStyle);
}
$("#content").find("*").hide();
$.each(selected, function(index,item) {
$('#content').find('[data-style *="' + item + '"]').show();
});
return false;
});
});
Both of your handlers are updating the selected array, but only one handler executes on a click. The first one if a color was (de)selected, the second if a style. Let's say you've clicked on "Black" and "Crew Neck". At that time your selected array would look like this: [ "Black", "Crew_Neck" ]. The next time you make a selection, let's say you click "Short Sleeves", the second (style) handler executes. Here's what is happening:
Short_Sleeves gets added to the selected array.
All of the items are hidden using $("#content").find("*").hide();
The selected array is iterated and items are shown again based on a dynamic selector.
Number 3 is the problem. In the above example, a style was clicked so the style handler is executing. Any items in the selected array that are colors will fail because, for example, no elements will be found with a selector such as $('#content').find('[data-style *="Black"]').show();.
I would suggest 2 things.
Keep 2 arrays of selections, one for color, one for style.
Combine your code to use only a single handler for both groups.
Here's a (mostly) working example.
Note that I added a data-type="color|style" to your .filterOptions containers to allow for combining to use a single handler and still know which group was changed.
Here's the full script:
$(document).ready(function () {
// use 2 arrays so the combined handler uses correct group
var selected = { color: [], style: [] };
// code was similar enough to combine to 1 handler for both groups
$('.filterOptions').on("click", "a", function (e) {
// figure out which group...
var type = $(e.delegateTarget).data("type");
var $this = $(this);
// ...and the value of the checkbox checked
var attrValue = $this.data(type);
// same as before but using 'type' to access the correct array
if ($this.parent().hasClass("active")) {
$this.parent().removeClass("active");
selected[type].splice(selected[type].indexOf(attrValue),1);
}
else {
$this.parent().addClass("active");
selected[type].push(attrValue);
}
// also showing all again if no more boxes are checked
if (attrValue == 'All' || $(".active", ".filterOptions").length == 0) {
$('#content').find('*').show();
}
else {
// hide 'em all
$("#content").find("*").hide();
// go through both style and color arrays
for (var key in selected) {
// and show any that have been checked
$.each(selected[key], function(index,item) {
$('#content').find('[data-' + key + ' *="' + item + '"]').show();
});
}
}
});
});
UPDATE: incorporating suggestions from comments
To make the handler work with checkboxes instead of links was a small change to the event binding code. It now uses the change method instead of click and listens for :checkbox elements instead of a:
$('.filterOptions').on("change", ":checkbox", function (e) {
// handler code
});
The "All" options "hiccup" was a little harder to fix than I thought it would be. Here's what I ended up with:
// get a jQuery object with all the options the user selected
var checked = $(":checked", ".filterOptions");
// show all of the available options if...
if (checked.length == 0 // ...no boxes are checked
|| // ...or...
checked.filter(".all").length > 0) // ...at least one "All" box is checked...
{
// remainder of code, including else block, unchanged
}
I also added an all class to the appropriate checkbox elements to simplify the above conditional.
Updated Fiddle

Show/hide div with specified text on mouseover/mouseout of copied div

I have a table which is copied verbatim from one div to another. I did this so that I could have a fixed table header with a scrollable body. The first div id is #headdiv and the second div class is .bodydiv, and the contents of #headdiv are duplicated into .bodydiv with this function:
$('.bodydiv').html($('#headdiv').html());
And then I modify the display/visibility properties of the two divs to make them look like one table. See here for the html and css: http://jsfiddle.net/jbswetnam/KNnAd/5/
Now, what I want to do is make some help text appear when the user hovers over cells in the table. I can do this with the following functions using element id's:
//Copied and modified from https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures
function showInfo(info, display) {
document.getElementById('infoBox').innerHTML = info;
document.getElementById('infoBox').style.display = display;
}
function makeInfoCallback(info, display) {
return function() {
showInfo(info, display);
};
}
function setupInfo() {
var infoText = [
{'id': 'header', 'info': 'Header Row'},
{'id': 'alpha', 'info': 'Alpha'}
];
for (var i = 0; i < infoText.length; i++) {
var item = infoText[i];
document.getElementById(item.id).onmouseover =
makeInfoCallback(item.info, "");
document.getElementById(item.id).onmouseout =
makeInfoCallback("", "none");
}
}
setupInfo();
As you can see at http://jsfiddle.net/jbswetnam/KNnAd/5/, when you hover over the table header, the text "Header Row" appears. What I'm trying to do is make the text "Alpha" appear when you hover over the cell that says "Alpha".
I know why the function works in the header and not the body. The header has an id which is referenced in the function above, whereas the body cells that you see are copied from #headdiv and therefore their id's are not valid. But I don't know enough about Javascript to know how to fix the problem. Using classes instead of id's doesn't work. I have a feeling that I can refactor the whole script using this and perhaps calling the function out of each cell, but I just don't know how to do that.
Any help would be appreciated!
Got it done with this code:
function makeInfo() {
$('.info').hover(
function() {
$('#infoBox').html($(this).attr('info'));
$('#infoBox').css('display', '');
},
function() {
$('#infoBox').css('display', 'none');
});
}
makeInfo();
You can see the updated HTML at the same jsfiddle.

Using jQuery to retrieve IDs of several DIVs and store in an array

I'm currently working on a "template" creation system with html, jQuery and PHP. So the interface is very basic, buttons that currently add divs, these divs are to have content such as buttons, textareas, checkboxes and such.
When I click a button, the div is added; now i also want to store this new div ID into an array with jQuery and at the same time output this array into a separate div with the ID of overview.
My current script looks like this:
function getSteps() {
$("#template").children().each(function(){
var kid = $(this);
//console.log(kid.attr('id'));
$('div.overview').append(kid.attr('id'))
});
}
$('button').on('click', function() {
var btnID = $(this).attr('id');
$('<div></div>', {
text: btnID,
id: btnID,
class: item,
}).appendTo('div.template');
});
$(document).ready(function() {
getSteps();
});
Now, the function getSteps is where I want to retrieve the ID's of all my divs and store them into an array. When I click one of my buttons, I want them to add a div with an ID into my #template div.
I get an error in my console in chrome:
Uncaught ReferenceError: item is not defined
(anonymous function)createtemplate.php:111
f.event.dispatchjquery.min.js:3
f.event.add.h.handle.i
I'm a bit lost and would love a push into the right direction. Thank you.
You could do (to retrieve the ID's of all the divs and store them into an array. )
function getSteps() {
var ids = [];
$("#template").children().each(function(){
ids.push(this.id);
});
return ids;
}
$(document).ready(function() {
var arrayOfIds = getSteps();
});
You get that error because you're trying to use a variable called item that doesn't exist. I guess you want to give a class called item, in which case you should write
class:"item",
Also, you're appending the new divs to a element with class "template", and your getSteps function is searching for an element with id "template".
Think that with your code, the getSteps function executes once, when the DOM is ready. If you want to refresh the list of id's every time you add a div, you should do it inside your code for click event:
function getSteps() {
$('div.overview').empty();
$(".template").children().each(function(){
var kid = $(this);
//console.log(kid.attr('id'));
$('div.overview').append(kid.attr('id'))
});
}
$(document).ready(function() {
$('button').on('click', function() {
var btnID = $(this).attr('id');
$('<div></div>', {
text: btnID,
id: btnID,
class: 'item',
}).appendTo('div.template');
getSteps();
});
});

Categories