Add active class to next sibling - javascript

Could someone help me with this, I am a bit stuck with JavaScript. Every time when someone is clicking on the question, the active class name should be added to the next sibling, but how to get that fixed. Only in plain JavaScript please. Any other frameworks do not count.
document.querySelector(".question").addEventListener("click", function() {
if(this.classList.contains("active")) {
this.classList.remove("active");
} else {
this.classList.add("active");
}
});
.faq-block .question,
.faq-block .answer {
border: 1px solid red;
padding: 10px;
}
.answer {
display: none;
}
.active {
display: block;
}
<div class="faq-block">
<div class="question">How do I cancel my order</div>
<div class="answer">Answer</div>
</div>
<div class="faq-block">
<div class="question">I am not getting an internet connection from my second SIM card</div>
<div class="answer">Answer</div>
</div>
<div class="faq-block">
<div class="question">My charger does not work and my device would not charge properly</div>
<div class="answer">Answer</div>
</div>
<div class="faq-block">
<div class="question">My fingerprint scanner is not working and does not respond when touched</div>
<div class="answer">Answer</div>
</div>

Use querySelectorAll ,document.querySelector will only select first matched element.
// get all matched element
var ques = document.querySelectorAll(".question")
// loop over the array to add event to each of the element
ques.forEach(function(item, index) {
// creating closure
(function(i) {
// adding event listerner to each element
ques[i].addEventListener("click", function() {
// this refers to the current selected element
if (this.classList.contains("active")) {
this.classList.remove("active");
} else {
this.classList.add("active");
}
});
}(index)) // passing the index to target element in the array
})
DEMO

Try this
document.querySelector(".question").addEventListener("click", function() {
if(this.classList.contains("active")) {
this.classList.remove("active");
this.nextSibling.classList.add("active")
} else {
this.nextSibling.classList.add("active");
}
});
I don't know why u need to do conditional checking. but to answer your question, you can use nextSibling

A simple adjustment to your CSS will do the trick:
.question.active+.answer {
display: block;
}
This will allow you to set the "active" class on the question, and let it reveal the answer.
Alternatively, use this.parentNode for the class, and then the CSS becomes:
.faq-block.active>.answer {
display: block;
}
This, I would argue, conveys more meaning too.

First of all document.querySelector(".question") returns the first element matching selector(documentation).
If i understood right you wanted to get .active class applied to Answers so here you are:
document.querySelectorAll(".question")
.forEach(element => element.addEventListener("click", function () {
nextNode = this.nextElementSibling;
if(!nextNode.classList.contains("active")){
nextNode.classList.add("active");
}
else{
nextNode.classList.remove('active');
}
})
);
JSFiddle

Related

Javascript set CSS Class for Multiple Elements (one element set, remaining elements unset)

I am developing a website which has a few filter buttons which are grouped into several groups. I am trying to find a way to set the class of one of these buttons to "filter-set" while all other buttons in the group are set to "not-set".
Each button is a DIV with a unique ID.
i have some bloated code where each button has its own function and sets the associated buttons to "not-set" but this seems inefficient and im sure there's a better way!
Bloated code example:
function setClassR(){
document.getElementById('filter_rare').className= 'filter-set';
document.getElementById('filter_common').className= 'not-set';
document.getElementById("filter_occasional").className = 'not-set';
}
function setClassC(){
document.getElementById('filter_rare').className= 'not-set';
document.getElementById('filter_common').className= 'filter-set';
document.getElementById("filter_occasional").className = 'not-set';
}
function setClassO(){
document.getElementById('filter_rare').className= 'not-set';
document.getElementById('filter_common').className= 'not-set';
document.getElementById("filter_occasional").className = 'filter-set';
}
I would like to be able to have a function for each group of filters which when run using an onClick=function() sets the clicked button to "filter-set" and all others to "not-set"
I have tried the following code but it doesnt appear to run:
function setClassSeas(rareClass, commonClass, occClass) {
setClass("filter_rare", rareClass);
setClass("filter_common", commonClass);
setClass("filter_occ", occClass);
}
function setClass(IDName, displayValue) {
var items = document.getElementById(IDName);
for (var i=0; i < items.length; i++) {
items[i].className = (displayValue? "filter-set" : "not-set");
}
}
UPDATE///
HTML Code for the Divs acting as buttons:
<div id="filter_rare" title="Rare"
class="not-set"
onclick="chosenFrequency('frequency=Rare'); setClassR();"></div>
<div id="filter_common" title="Common"
class="not-set"
onclick="chosenFrequency('frequency=Common'); setClassC();"></div>
<div id="filter_occasional" title="Occasional"
class="not-set"
onclick="chosenFrequency('frequency=Occasional'); setClassO();"></div>
If every button has a class, say filter-button, then you can address all buttons at once.
In modern development you should attach an event handler instead of using inline onclick handlers.
With all buttons having a common class you can find them all at once. I'm changing your buttons to look like this, adding the "filter-button" class and removing the onclick handler:
<div id="filter_rare" title="Rare"
class="filter-button not-set">Rare</div>
(I've put text in the div just to simplify this demonstration)
Now collect all the filter buttons:
let filters = document.querySelectorAll('div.filter-button');
This gets you a NodeList of elements (kind of like an Array but not one) You'll want to attach an onclick event handler to each of the buttons. To do this you can use the NodeList.forEach() call.
filters.forEach(node => node.addEventListener('click', someFunction));
In the function that gets called when you click a button, you want to clear any filter-set class that's currently set, put back the original not-set class, then set the filter-set class only on the button that was clicked. This will look something like this:
function someFunction(event) {
// again, use forEach to do the same thing to each filter button
filters.forEach( function(node) {
node.classList.remove('filter-set');
node.classList.add('not-set');
} );
// now add the 'filter-set' class on the button that was clicked
event.target.classList.add('filter-set');
}
The good thing about using classList instead of just doing className="something" is that classList can add/remove classes while leaving other classes alone; doing className="something" wipes out all the classes that are present and replaces them with "something".
Putting that all together, and using an anonymous function instead of named function gives this snippet:
let filters = document.querySelectorAll('div.filter-button');
filters.forEach(node => node.addEventListener('click',
function(event) {
console.log(event.target);
filters.forEach(function(node) {
node.classList.remove('filter-set');
node.classList.add('not-set');
});
event.target.classList.add('filter-set');
}));
/* Make these look like buttons; put a green border on them */
.filter-button {
min-height: 2ex;
max-width: 12em;
padding: .25em;
margin: .7em .3em;
background-color: lightgreen;
border: 2px solid green;
border-radius: 4px;
}
/* use a Red border on any button that has "filter-set" */
.filter-button.filter-set {
border: 2px solid red;
}
/* limit the height of the stack-snippet console */
div.as-console-wrapper {
max-height: 2.5em;
}
<div id="filter_rare" title="Rare"
class="filter-button not-set">Rare</div>
<div id="filter_common" title="Common"
class="filter-button not-set">Common</div>
<div id="filter_occasional" title="Occasional"
class="filter-button not-set">Occasional</div>
Using the class not-set is really redundant — you could just have no extra class on buttons by default and it would simplify things a little. Buttons would have the class(es) filter-button or filter-button filter-set.
Change your setClass function according to this. Hope it will work. document.getElementById() function will always return a single element (not a list of elements). Even if you have multiple elements having the same ID this function will always return the first element having the given ID. Do not forget to call your setClassSeas() function from html.
function setClassSeas(rareClass, commonClass, occClass) {
setClass("filter_rare", rareClass);
setClass("filter_common", commonClass);
setClass("filter_occ", occClass);
}
function setClass(IDName, displayValue) {
var item = document.getElementById(IDName);
item.className = displayValue ? "filter-set" : "not-set";
}
<div id="filter_rare" title="Rare" class="not-set"
onclick="chosenFrequency('frequency=Rare'); setClassSeas(true, false, false);"></div>
<div id="filter_common" title="Common" class="not-set"
onclick="chosenFrequency('frequency=Common'); setClassSeas(false, true, false);"></div>
<div id="filter_occasional" title="Occasional" class="not-set"
onclick="chosenFrequency('frequency=Occasional'); setClassSeas(false, false, true);"></div>
Here is another (as in "alternative") way to do it (but with jQuery, oh no!)
$('body').click(function(e) {
let $clicked = $(e.target);
console.log("Clicked " + $clicked.attr('id'))
if ($clicked.hasClass('filter')) {
let $filters = $clicked.closest('.filter-group').find('.filter');
let unset = $clicked.hasClass('set');
$filters.toggleClass('not-set', true);
$filters.toggleClass('set', false);
if (!unset) {
$clicked.toggleClass('not-set', false);
$clicked.toggleClass('set', true);
}
}
})
button.filter.not-set {
background: white;
}
button.filter.set {
color: white;
background: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="filter-group">
<button id="filter_rare" class="filter not-set">
filter_rare
</button>
<button id="filter_common" class="filter not-set">
filter_common
</button>
<button id="filter_occasional" class="filter not-set">
filter_occasional
</button>
</div>
<div class="filter-group">
<button id="filter_one" class="filter not-set">
filter_one
</button>
<button id="filter_two" class="filter not-set">
filter_two
</button>
<button id="filter_three" class="filter not-set">
filter_three
</button>
</div>

How to add a class to a div on click, and remove the class by clicking elsewhere on the page

I would like to expand a div, filters, when filtertoggle is clicked. I would like to do this by adding the class on to filters. Then, when the user clicks anywhere else on the page, I would like to remove the on class, thereby closing filters.
Here is the code I have attempted:
jQuery(document).ready(function($) {
$('body').click(function(evt) {
if (evt.target.attr('class').includes('filtertoggle')) {
$(this).toggleClass('on');
$('.filters').slideToggle(200);
return;
} else {
$(this).element.className = element.className.replace(/\bon\b/g, "");
return;
});
As it stands, filters does not open.
Your logic has a couple of issues. Firstly, evt.target is an Element object, not a jQuery object, so it has not attr() method. You need to wrap it in a jQuery object to make that work. Then you can use hasClass() to check what class is on the target.
Also a jQuery object has no element property, so element.className will cause a syntax error. You can just use removeClass() in that case. Try this:
$('body').click(function(evt) {
if ($(evt.target).hasClass('filtertoggle')) {
$('.filtertoggle').addClass('on');
$('.filters').slideToggle(200);
} else {
$('.filtertoggle').removeClass('on');
$('.filters').slideUp(200);
}
});
body, html { height: 100%; }
.on { color: #C00; }
.filters { display: none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="filtertoggle">
FilterToggle
</div>
<div class="filters">
Filters...
</div>
You should also note that it may be possible to achieve this in CSS alone, depending on how your HTML is structured. You can use the :focus selector to do it, like this:
body, html { height: 100%; }
.filtertoggle { outline: 0; }
.filters {
opacity: 0;
transition: opacity 0.3s;
}
.filtertoggle:focus { color: #C00; }
.filtertoggle:focus + .filters { opacity: 1; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="filtertoggle" tabindex="1">
FilterToggle
</div>
<div class="filters">
Filters...
</div>

javascript don't .toggleClass() if clicked again?

I've put this in the simplest terms for this question.
if element is clicked, 'active' class is added to element, 'active' class is removed from other elements.
However, if the element is 'active' and it's clicked for a second time the 'active' class should not be "re-applied" (or called for a second time).
$(".class").click(function(){
$('.class').not(this).removeClass('active');
$(this).addClass('active');
}
For example when button 1 is clicked and has the 'active' class -> doFunction;
if ( $(".active").is("#1") ) {
doFunction();
}
when it's clicked again, a second time, the function is fired again even though the element is already 'active'. If the element is active and is clicked a second time I don't want to call the functions again. How can I achieve this?
Codepen Example: https://codepen.io/anon/pen/yvZXOB?editors=1111
Thanks!
Since you didn't specify exactly how you want to limit the functions from being called, let's look at two possibilities.
First possibility: each button you can click to activate and call some function at most one time. After that, toggling buttons will toggle the classes but not calling the other function again.
In this scenario, you can use jQuery's .one().
$(".class").one('click', function(){
$('.class').not(this).removeClass('active');
$(this).addClass('active');
if ( $(".active").is("#1") ) {
doFunction();
}
if ( $(".active").is("#2") ) {
doFunction();
}
function doFunction() {
console.log("function fired!");
}
});
.class {
padding: 10px;
border-radius: 5px;
background: #392;
width: 100px;
color: white;
text-align: center;
margin: 25px;
display: inline-block;
cursor: pointer;
}
.active {
background: #932;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="class" id="1">
button
</div>
<div class="class" id="2">
another
</div>
Second possibility: when you click between buttons, the active state is toggled, but clicking a button that's already active won't keep running the other function. However, toggling away from a button and back to it will allow that button's function to run again.
In this case, you can set some kind of flag via a variable and then check the flag to see if you're allowed to run the other function again. Function runs, flag goes up. Different button gets clicked, flag goes back down.
var preventFunction;
$(".class").on('click', function(){
if($(this).hasClass('active')) {
preventFunction = true;
} else {
preventFunction = false;
}
$('.class').not(this).removeClass('active');
$(this).addClass('active');
if ( $(".active").is("#1") ) {
if(preventFunction !== true) {
doFunctionOne();
}
}
if ( $(".active").is("#2") ) {
if(preventFunction !== true) {
doFunctionTwo();
}
}
});
function doFunctionOne() {
console.log("function one fired!");
preventFunctiong = true;
}
function doFunctionTwo() {
console.log("function two fired!");
preventFunction = true;
}
.class {
padding: 10px;
border-radius: 5px;
background: #392;
width: 100px;
color: white;
text-align: center;
margin: 25px;
display: inline-block;
cursor: pointer;
}
.active {
background: #932;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="class" id="1">
button
</div>
<div class="class" id="2">
another
</div>
Since you are dynamically adding/removing classes, the correct apporach is to use event delegation like this:
$(document).on('click', ".class:not(.active)", function(){
$('.class').removeClass('active');
$(this).addClass('active');
console.log("click triggered!");
})
https://codepen.io/connexo/pen/PQVKNY?editors=1111
This trick will work(just use one global variable and hold the last active item's id),
var last_act_id = 0;
$(".class").click(function(){
if($(this).attr('id') != last_act_id) {
last_act_id = $(this).attr('id');
$('.class').removeClass('active');
$(this).addClass('active');
doFunction();
}
function doFunction() {
console.log("function fired!");
}
});
Demo: https://codepen.io/anon/pen/Nyovjr?editors=0001
Just check to see if that event target has the class already. Since you're using jQuery you could do something like
if($('.selector').hasClass('active')) {
$('.selector').removeClass('active')
} else {
$('.selector').addClass('active')
}
Try this
$("#1").click(function(){
$('#2').removeClass('active');
if (!$("#1").hasClass('active')) {
$("#1").addClass('active');
doFunction();
}else{
console.log("already clicked");
}
});
$("#2").click(function(){
$('#1').removeClass('active');
if (!$("#2").hasClass('active')) {
$("#2").addClass('active');
doFunction();
}else{
console.log("already clicked");
}
});
function doFunction() {
console.log("function fired!");
}
I hope it helps

Swapping text equal in different divs and classes

I have several boxes of cards on one page, these boxes can come dynamically in different, not upper right corner has a text for the click to open the accordion type content, for each class I have to do an action as below, I think of something Regardless of the number of classes.
*new
I do not know how to explain it, I'll try a summary:
Change the text of only one div when clicking, because when I click on the item in the box it changes all the other texts of the
Other boxes.
$('.change-1').click(function () {
var $mudartxt = $('.mudartexto');
if ($mudartxt.text() == 'expandir')
$mudartxt.text('ocultar');
else {
$mudartxt.text('expandir');
}
});
You need to find the current clicked item.
For that you can use the event object
$('.change-1').click(function (e) {
// Get current target as jquery object
var $target = $(e.currentTarget);
// Find mudartexto in current target.
var $mudartxt = $target.find('.mudartexto');
if ($mudartxt.text() == 'expandir')
$mudartxt.text('ocultar');
else {
$mudartxt.text('expandir');
}
});
.change-1 {
display:inline-block;
width:200px;
height:50px;
text-align: center;
background-color:#dfdfdf;
clear: both;
float: left;
margin-top:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="change-1">
<div class="mudartexto">expandir</div>
</div>
<div class="change-1">
<div class="mudartexto">expandir</div>
</div>
<div class="change-1">
<div class="mudartexto">expandir</div>
</div>
<div class="change-1">
<div class="mudartexto">expandir</div>
</div>
If you are asking how to change text of an element, inside a clicked box, this should do it.
$('.change-1').click(function () {
var $mudartxt = $(this).find('.mudartexto');
if ($mudartxt.text() == 'expandir')
$mudartxt.text('ocultar');
else {
$mudartxt.text('expandir');
}
});

Remove all span elements by classname?

I have a classname called notag. When i click a button, it triggers my onclick event to call my function. Within the function i want it to remove / delete all span elements that has that classname notag.
My attempts are below but no luck! Please help thanks.
onclick="replaceQueuePlaylist()"
function replaceQueuePlaylist()
{
$("span").attr('notag').remove(); //dont work
$('.notag').remove(); //also dont work
}
$("span").attr('notag').remove(); //dont work
This won't work because your elements have a class named notag, and not an attribute. class itself is an attribute with value notag in <div class='notag'> hello world </div>
There's no need to explicitly use .each() as using $(selector).remove() will automatically iterate through each element with the selection criteria and remove it.
$('#delete-em').on('click', function(){
$('.delete-me').remove();
});
.delete-me{
height: 50px;
width: 50px;
margin: 5px;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class='delete-me'></div>
<div class='delete-me'></div>
<div class='delete-me'></div>
<div class='delete-me'></div>
<button id="delete-em">Remove</button>
With jQuery.remove() you can directly remove all the set of matched elements from the DOM:
function replaceQueuePlaylist() {
$('span.notag').remove();
}
Try this one;
function replaceQueuePlaylist() {
$("span.notag").each(function () {
$(this).remove();
});
}
Finds all the spans with notag class name and delete them.
Just add these lines in your function. Happy coding
$("span.notag").each(function () {
$(this).remove();
});

Categories