Several conditions filter on javascript/jquery - javascript

I am stuck with this problem. There is a simple filter and it works not exactly the way I need it: http://jsfiddle.net/qyy810xx/
CSS here:
.categorya, .categoryb, .categoryrko {
width: 30px;
height: 20px;
line-height:20px;
text-align:center;
background: red;
margin: 10px;
float: left;
font-size:11px;
color:white;
font-family:sans-serif;
}
.categoryb {
background: blue;
}
.categorya.categoryb{
background:purple;
}
p.info{
padding:30px 20px 0 20px;
color:#666;
font-family:sans-serif;
font-size:13px;
}
HTML:
<ul id="filters">
<li>
<input type="checkbox" value="categorya" id="filter-categorya" />
<label for="filter-categorya">Category A</label>
</li>
<li>
<input type="checkbox" value="categoryb" id="filter-categoryb" />
<label for="filter-categoryb">Category B</label>
</li>
<li>
<input type="checkbox" value="categoryrko" id="filter-categoryrko" />
<label for="filter-categoryrko">RKO</label>
</li>
</ul>
<div class="categorya categoryb">A, B</div>
<div class="categorya">A</div>
<div class="categorya">A</div>
<div class="categorya">A</div>
<div class="categoryrko">RKO</div>
<div class="categoryb categoryrko">BRko</div>
<div class="categoryb">B</div>
<div class="categoryb">B</div>
And script:
$("#filters :checkbox").click(function() {
var re = new RegExp($("#filters :checkbox:checked").map(function() {
return this.value;
}).get().join("|") );
$("div").each(function() {
var $this = $(this);
$this[re.source!="" && re.test($this.attr("class")) ? "show" : "hide"]();
});
});
If select categoryB we can see ONLY divs with categoryB class, but i need to see all divs, including categoryB class.
e.g. if you select categoryA it must display [A,B] block, all [A] blocks and [RKOa] block, but if you select categoryA AND categoryRKO it must show ONLY [RKOa] block. i.e. only a block that satisfies all parameters.
I will be glad to any help

You need not make a regular expression, just formulate a selector using the same logic
$("#filters :checkbox").click(function() {
var selector = $("#filters :checkbox:checked").map(function() {
return "." + this.value;
}).get().join(",");
$("div").hide().filter(selector).show(); //now show only those which are matching the selector chosen above
});

I know what you're trying to do. But be honest your code was really hard for other to read. So I decided to come up with a better solution and easy for everyone to know what I'm trying to do when they're reading code.
The idea is: Every times you check a checkbox.
You map through all checkboxes and push the value of checked checkbox into an array.
Then hide all div
And finally loop through an array and show the checked one.
Here is modified code of your's. :) Hope it can give you a idea.
$(".filter-checkbox").click(function() {
var checkboxes = $('.filter-checkbox');
var checkedClasses = [];
//Map and get all checked category
var activeCheckboxes = checkboxes.each(function(index,checkbox){
if(checkbox.checked)
checkedClasses.push(checkbox.value);
});
//Hide all category
$('.category').hide();
//Show only checked
$.each(checkedClasses,function(index,className){
$('.' + className).show();
})
});
.categorya, .categoryb, .categoryrko {
width: 30px;
height: 20px;
line-height:20px;
text-align:center;
background: red;
margin: 10px;
float: left;
font-size:11px;
color:white;
font-family:sans-serif;
}
.categoryb {
background: blue;
}
.categorya.categoryb{
background:purple;
}
p.info{
padding:30px 20px 0 20px;
color:#666;
font-family:sans-serif;
font-size:13px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="filters">
<li>
<input class="filter-checkbox" type="checkbox" value="categorya" id="filter-categorya" />
<label for="filter-categorya">Category A</label>
</li>
<li>
<input class="filter-checkbox" type="checkbox" value="categoryb" id="filter-categoryb" />
<label for="filter-categoryb">Category B</label>
</li>
<li>
<input class="filter-checkbox" type="checkbox" value="categoryrko" id="filter-categoryrko" />
<label for="filter-categoryrko">RKO</label>
</li>
</ul>
<div class="category categorya categoryb">A, B</div>
<div class="category categorya">A</div>
<div class="category categorya">A</div>
<div class="category categorya">A</div>
<div class="category categoryrko">RKO</div>
<div class="category categoryb">B</div>
<div class="category categoryb">B</div>
<div class="category categoryb">B</div>
<br />
<p class="info">
- If you select Category A: four boxes will apear [A,B] [A] [A] [A]
<br/><br/>
- Then if you select Category B and deselect it again: the purple box [A,B] will disapear because the script commands to hide 'B'.
<br/><br/>
- But I don't want the script to hide box 'B' when it also contains 'A'..
</p>

Related

Get the value of checkboxes in a specific section using javascipt

I have a page that contain different section these section appear when the user click on li an active class is added to the section and then this section appear
each section contain a box with checkboxes and a link to another page when i click on this link i should store the value of the checkboxes for the section active only to print them later
all the code work fine but my problem is that i only can have the checkbox value for the first section that contain active class by defaul
how can i solve that please?
/*Put active class on li click for section*/
let tabs = document.querySelectorAll(".nav li");
let tabsArray = Array.from(tabs);
let section = document.querySelectorAll(".section");
let sectionArray = Array.from(section);
tabsArray.forEach((ele) => {
ele.addEventListener("click", function (e) {
tabsArray.forEach((ele) => {
ele.classList.remove("active");
});
e.currentTarget.classList.add("active");
sectionArray.forEach((sec) => {
sec.classList.remove("active");
});
document.querySelector('#' + e.currentTarget.dataset.cont).classList.add("active");
});
});
/*put the check box value in localstorage to print them later*/
let printBtn = document.querySelector(".active .btn-print");
let terms = document.querySelectorAll(".active input[type='checkbox']");
let termsValChecked = [];
let termsValUnChecked = [];
printBtn.addEventListener("click", function (e) {
localStorage.removeItem("termschecked");
localStorage.removeItem("termsunchecked");
for (let i = 0; i < terms.length; i++) {
if (terms[i].checked == true) {
termsValChecked.push(terms[i].value);
} else {
termsValUnChecked.push(terms[i].value);
}
}
window.localStorage.setItem("termschecked", JSON.stringify(termsValChecked));
window.localStorage.setItem("termsunchecked", JSON.stringify(termsValUnChecked));
});
.box {
display: flex;
align-items: center;
}
section {
display: none;
}
section.active {
display: block;
}
.nav {
list-style:none;
display: flex;
align-items: center;
}
.nav li {
padding: 20px;
background-color: #ccc;
margin-left: 2px;
cursor: pointer;
}
<ul class="nav">
<li data-cont="r1">1</li>
<li data-cont="r2">2</li>
<li data-cont="r3">3</li>
</ul>
<section class="section section-one active" id="r1">
<h3>Section 1</h3>
<div class="box">
<input type="checkbox" value="test1">
<p>test1</p>
</div>
<div class="box">
<input type="checkbox" value="test2">
<p>test2</p>
</div>
<div class="print">
Print
</div>
</section>
<section class="section section-two" id="r2">
<h3>Section 2</h3>
<div class="box">
<input type="checkbox" value="test3">
<p>test3</p>
</div>
<div class="box">
<input type="checkbox" value="test4">
<p>test4</p>
</div>
<div class="print">
Print
</div>
</section>
<section class="section section-three" id="r3">
<h3>Section 3</h3>
<div class="box">
<input type="checkbox" value="test5">
<p>test5</p>
</div>
<div class="box">
<input type="checkbox" value="test6">
<p>test6</p>
</div>
<div class="print">
Print
</div>
</section>
querySelectorAll returns a static NodeList, i.e. the list will reflect the state at invocation and won't update if the page later changes.
The following line runs when you initialize your page:
let terms = document.querySelectorAll(".active input[type='checkbox']");
And that's why you always capture the first section in local storage.
You need to move this line inside your click handler so that you enumerate the checkboxes inside the .active section at that time.
Remove the Attribute ".change" from your selector on line 23
simply change
let terms = document.querySelectorAll(".active input[type='checkbox']");
to
let terms = document.querySelectorAll("input[type='checkbox']");

Javascript : finding a specific previous element on list and adding class

I have a list like this.
Inside each .list item there is a html button :
<div class="list">
<button>.list</button>
</div>
Also, each item can be inside a .bloc element
<div class="list"><button>.list</button></div>
<div class=bloc>
<div class="list"><button>.list</button></div>
</div>
When I click on the button, I would like the previous .list item to have the .active class like so :
Well it’s pretty easy with jquery and i've done that, it’s work pretty well :
$('.list button').on('click', function() {
$(this).closest('.list').prev('.list').addClass('active');
});
BUT i have some specific cases :
Sometimes the list items can be hidden and a list with hidden class can’t have .active class :
Or more complicated. You have to go up on each item one by one and put the active class to the first which does not have the hidden class :
I did the mechanics for items without class hidden, but I'm afraid I'm going in the wrong direction because the number of cases is getting bigger and bigger. Ain't there a smarter way ? :o
$('.list button').on('click', function() {
if ($(this).closest('.list').prev().length === 0) {
if ($(this).closest('.bloc').length) {
$(this).closest('.bloc').prev('.list').addClass('active');
$(this).closest('.bloc').prev('.bloc').find('.list:last-child').addClass('active');
} else {
$(this).closest('.list').next('.list').addClass('active');
}
}
if ($(this).closest('.list').prev('.bloc').length) {
$(this).closest('.list').prev('.bloc').find('.list:last-child').addClass('active');
}
$(this).closest('.list').prev('.list').addClass('active');
}
Rather than use .closest .prev and .next you can use the overload to .index which will give you the index within an existing collection.
var idx = collection.index(element);
select all your .list items into a jquery object/collection
when clicking get the index within that collection
subtract 1 to get the previous .list item within that collection
The basic scenarios are covered with $(".list") :
// collate the list first
var list = $(".list");
// add click handler
list.click(function() {
// confirm there are no duplicates
// comapred with $(this).index() which is the index within the parent
console.log(list.index(this), $(this).index())
$(".active").removeClass("active");
var idx = list.index(this);
if (idx > 0)
list.eq(idx-1).addClass("active");
});
.list { border:1px solid #CCC; height: 20px; }
.bloc { border:1px solid #444; padding: 5px; }
.active { border:1px solid red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='wrapper'>
<div class='bloc'>
<div class='list'></div>
<div class='list'></div>
</div>
<div class='list'></div>
<div class='list'></div>
</div>
All the other use-cases are then just a case of providing the correct selector up-front, with otherwise exactly the same code
var list = $(".wrapper>.bloc:not(.hidden)>.list:not(.hidden),.wrapper>.list:not(.hidden)");
I've tried to recreate some of your scenarios, but if there's one that's missing, please comment and I'll ensure it fits (within the remit of the question).
Giving:
var list = $(".wrapper>.bloc:not(.hidden)>.list:not(.hidden),.wrapper>.list:not(.hidden)")
list.click(function() {
$(".active").removeClass("active");
var idx = list.index(this);
if (idx > 0)
list.eq(idx-1).addClass("active");
});
.list { border:1px solid #CCC; height: 20px; }
.bloc { border:1px solid #444; padding: 5px; }
.active { border:1px solid red; }
.hidden { background-color: #ccc; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='wrapper'>
<div class='bloc'>
<div class='list'></div>
<div class='list'></div>
</div>
<div class='list hidden'></div>
<div class='bloc'>
<div class='list hidden'></div>
<div class='list hidden'></div>
</div>
<div class='list'></div>
<div class='bloc'>
<div class='list hidden'></div>
<div class='list'></div>
</div>
<div class='list'></div>
<div class='list'></div>
<div class='bloc hidden'>
<div class='list'></div>
<div class='list'></div>
</div>
<div class='list'></div>
<div class='list'></div>
</div>

Css on clickable element (*[onclick]:hover)

I want to use to style my clickable element (javascript function onclick), when they hovered.
So far I have this :
*[onclick]:hover{
background-color: red ;
color: blue;
}
It works fine for most of my elements as you can see :
document.getElementById('C').onclick = function(){alert('I am clickable too !')}
div {
background-color: green ;
margin : 2px
}
*[onclick]:hover{
background-color: red ;
color: blue;
}
<div id="A" onclick='alert("A")'>Click me ! A</div>
<div id="B" onclick='alert("B")'>Click me ! B</div>
<div id="notAclickableElement" >Don't click me :( Z</div>
<div id="C" >Click me ! C</div>
<div id="D" onclick='alert("D")'>Click me ! D</div>
But it only work for element where the onclick function is written in the Html page, and not added via Javascript.
Is there a way to properly select all clickable elements ?
The browser know a handful of elements that can be clicked by default, like the <a> and <button> elements. It is usually a good practice to use these elements if you want the user the click them, as they require little work to modify.
Other than that you could just add a class to the elements which to target them with as there is not a selector for an element that can be clicked.
However, it is a good practice to add a tabindex attribute to the elements that can be clicked as it makes them focusable. Users without a mouse (they exist) can use the Tab key to cycle through the clickable elements and click them with Enter or Spacebar. The elements mentioned in the first paragraph already incorporate this natively. With <div> elements you'll have to add this behavior manually.
The example below targets all clickable elements with a class and adds the :focus selector for the focussed styles.
document.getElementById('C').onclick = function() {
alert('I am clickable too !')
}
div {
background-color: green;
margin: 2px
}
.clickable:hover {
background-color: red;
color: blue;
}
.clickable:focus {
background-color: blue;
color: red;
}
<div id="A" class="clickable" onclick='alert("A")' tabindex="0">Click me ! A</div>
<div id="B" class="clickable" onclick='alert("B")' tabindex="0">Click me ! B</div>
<div id="notAclickableElement">Don't click me :( Z</div>
<div id="C" class="clickable" tabindex="0">Click me ! C</div>
<div id="D" class="clickable" onclick='alert("D")' tabindex="0">Click me ! D</div>
Sure. Just remove the [onclick] in the CSS.
document.getElementById('C').onclick = function(){alert('I am clickable too !')}
div {
background-color: green ;
margin : 2px
}
*:hover{
background-color: red ;
color: blue;
}
<div id="A" onclick='alert("A")'>Click me ! A</div>
<div id="B" onclick='alert("B")'>Click me ! B</div>
<div id="notAclickableElement" >Don't click me :( Z</div>
<div id="C" >Click me ! C</div>
<div id="D" onclick='alert("D")'>Click me ! D</div>
However, that also changed the background too, so we can designate a specific class to the divs like so:
document.getElementById('C').onclick = function(){alert('I am clickable too !')}
div {
background-color: green ;
margin : 2px
}
.hoverme:hover{
background-color: red ;
color: blue;
}
<div class="hoverme" id="A" onclick='alert("A")'>Click me ! A</div>
<div class="hoverme" id="B" onclick='alert("B")'>Click me ! B</div>
<div class="hoverme" id="notAclickableElement" >Don't click me :( Z</div>
<div class="hoverme" id="C" >Click me ! C</div>
<div class="hoverme" id="D" onclick='alert("D")'>Click me ! D</div>
Designating the hover to a single class is much more efficient, because you can define different hover effects for different things. All you have to do is add class="hoverme"
You can use .class in CSS.
document.getElementById('C').onclick = function(){alert('I am clickable too !')}
div {
background-color: green ;
margin : 2px
}
*[onclick]:hover{
background-color: red ;
color: blue;
}
.click {
background-color: green;
}
.click:hover {
background-color: red;
}
<div class="click" id="A" onclick='alert("A")'>Click me ! A</div>
<div id="B" onclick='alert("B")'>Click me ! B</div>
<div class="click" id="notAclickableElement" >Don't click me :( Z</div>
<div class="click" id="C" >Click me ! C</div>
<div class="click" id="D" onclick='alert("D")'>Click me ! D</div>
I hope I have been helpful
var x = document.querySelectorAll("div");
for (let i = 0; i < x.length; i++) {
if (x[i].id !== 'notAclickableElement') {
x[i].setAttribute('class', 'clickclass');
}
}
document.getElementById('C').addEventListener("click", hoverMe);
function hoverMe() {
alert('I am clickable too !')
}
div {
background-color: green;
margin: 2px
}
.clickclass:hover {
background-color: red;
color: blue;
}
<div id="A" onclick='alert("A")'>Click me ! A</div>
<div id="B" onclick='alert("B")'>Click me ! B</div>
<div id="notAclickableElement">Don't click me :( Z</div>
<div id="C">Click me ! C</div>
<div id="D" onclick='alert("D")'>Click me ! D</div>

Filter works not excluding results

I have simple js filter that you can see here: http://jsfiddle.net/qyy810xx/
So i've stucked with separation of filter's results. I mean that i need to have this:
1) If checked category A, we can see div class="categorya" only;
2) If checked category B, we can see div class="categoryb" only;
3) If checked category A and category B, we can see div class="categorya categoryb" only
I'm not very good at jquery, so this will be fine if you offer any solution.
Thank you!
$("#filters :checkbox").click(function() {
var re = new RegExp($("#filters :checkbox:checked").map(function() {
return this.value;
}).get().join("|"));
$("div.bankomat-f").each(function() {
var $this = $(this);
$this[re.source != "" && re.test($this.attr("class")) ? "show" : "hide"]();
});
});
.categorya,
.categoryb,
.categoryrko,
.categoryab,
.categorybb,
.categoryrkob {
width: 30px;
height: 20px;
line-height: 20px;
text-align: center;
background: red;
margin: 10px;
float: left;
font-size: 11px;
color: white;
font-family: sans-serif;
}
.categoryb,
.categorybb {
background: blue;
}
.categorya.categoryb {
background: purple;
}
#filters-b {
display: inline-box;
float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="filters">
<li>
<input type="checkbox" value="categorya" id="filter-categorya" />
<label for="filter-categorya">Category A</label>
</li>
<li>
<input type="checkbox" value="categoryb" id="filter-categoryb" />
<label for="filter-categoryb">Category B</label>
</li>
<li>
<input type="checkbox" value="categoryrko" id="filter-categoryrko" />
<label for="filter-categoryrko">RKO</label>
</li>
</ul>
<div class="bankomat-f categorya categoryb">A, B</div>
<div class="bankomat-f categorya">A</div>
<div class="bankomat-f categorya">A</div>
<div class="bankomat-f categorya">A</div>
<div class="bankomat-f categoryrko">RKO</div>
<div class="bankomat-f categoryb">B</div>
<div class="bankomat-f categoryb">B</div>
<div class="bankomat-f categoryb">B</div>

How to hide div when it's already open?

I couldn't think of any better title, so I will try to explain my question here as clear as possible. I'm quite a newbie in JQuery so this is probably a very easy question.
I have some divs with a button on it. When you click the button, another div should pop-up.
My question is: How can I make the div, which is already open, close when clicking on another button?
I made a fiddle with some example code: http://jsfiddle.net/zuvjx775/1/
And the example code here:
HTML:
<div class="wrapper">
<div class="test">
<input type='button' class='showDiv' id="1" value='click!' />
</div>
<div class="show_1">
</div>
</div>
<br>
<div class="wrapper">
<div class="test">
<input type='button' class='showDiv' id="2"value='click!' />
</div>
<div class="show_2">
</div>
</div>
JQuery:
$('.showDiv').on('click', function(){
var id = $(this).attr('id');
$('.show_'+id).show();
});
When show_1 for example is visible, and I click on the button in div2, I want show_2 to come up, which it does, but show_1 to dissapear.
Can someone point me in the right direction?
You can hide all divs that their class starts with 'show' before show the one you want. For example:
$('.showDiv').on('click', function() {
var id = $(this).attr('id');
$("div[class^='show']").hide();//find div class starts with 'show' and hide them
$('.show_' + id).show();
});
.test {
border: 1px solid black;
height: 100px;
width: 450px;
float: left;
}
.show_1 {
width: 50px;
height: 50px;
background-color: yellow;
float: left;
display: none;
}
.show_2 {
width: 50px;
height: 50px;
background-color: green;
float: left;
display: none;
}
.wrapper {
clear: both;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="test">
<input type='button' class='showDiv' id="1" value='click!' />
</div>
<div class="show_1">
</div>
</div>
<br>
<div class="wrapper">
<div class="test">
<input type='button' class='showDiv' id="2" value='click!' />
</div>
<div class="show_2">
</div>
</div>
Is the structure of the document fixed?
is so... I guess the easiest way of doing this is to just do the following:
$('.showDiv').on('click', function(){
var id = $(this).attr('id');
if(id == 1){
$('.show_1').show();
$('.show_2').hide();
}else{
$('.show_2').show();
$('.show_1').hide();
}
})

Categories