How to target next element with class name? - javascript

DEMO
I am doing a simple jquery accordian effect as below.
JQUERY
$(function ($) {
$('.Accordian').find('.Btn').click(function () {
$(this).next('.Content').slideToggle('fast');
$('.Content').not($(this).next()).slideUp('fast');
});
});
HTML
<div class="Accordian">
<div class="Btn"></div>
<div class="Content"></div>
</div>
This work great however if content is placed between .Btn and .Content then it breaks.
QUESTION
How to directly target the next available class name relative to the
button clicked?
How to target all elements of a class name except the next available
class name relative to button clicked?

Try with siblings()
$(function ($) {
$('.Accordian').find('.Btn').click(function () {
//cache the value so that it can be used in the next statement
var $content = $(this).siblings('.Content').slideToggle('fast');
$('.Content').not($content).slideUp('fast');
});
});

Try to use .nextAll() along with .first() to accomplish your task, Actually here we have used .first() for a safety purpose.
$('.Accordian').find('.Btn').click(function () {
var targetElem = $(this).nextAll('.Content').first();
targetElem.slideToggle('fast');
$('.Content').not(targetElem).slideUp('fast');
});
DEMO

Related

Add class to the clicked div with multiple divs with same class

How do I get the clicked div if the divs both got same class.
For an example:
<div class="box"></div> <div class="box"></div>
And I want to add another class to the div I click on.
New at JavaScript but I have figured out that I should use "this" in some way.
What I have done so far:
box = document.getElementById("box");
box.addEventListener("click, function(event) {
event.target.classList.toggle("clicked");
}
But of course this only works for a div with an Id and not for multiple divs.
You can use document.querySelectorAll here like:
var boxes = document.querySelectorAll('.box');
Array.from(boxes).forEach(box => {
box.addEventListener('click', function(e) {
e.target.classList.toggle('clicked');
});
});
If you want to use document.getElementById() you need to add element the id attribute:
<div id="box1" class="box">
By design, ids are meant to be unique, so if you can assign each element an id, it shoud be enough.
I'd suggest an approach where you add the listener on a parent (or whole document) and check for the clicked element inside:
document.addEventListener('click', function (event) {
if(event.target.classList.contains('box')) {
event.target.classList.toggle('clicked');
}
}
This approach is better performance-wise as it creates only one event handler, not a handler per element.
with jquery
$('.box').click(function() {
console.log($(this).text());
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">one</div><div class="box">two</div>
If you want to keep using pure JavaScript without any additional lib, I believe Query Selectores should help you (https://developer.mozilla.org/pt-BR/docs/Web/API/Element/querySelectorAll).
Evolving your snippet:
document.querySelectorAll("box").forEach( function (){
this.addEventListener('click', function(event) {
event.target.classList.toggle("clicked");
});
});
If you attach the eventListener onto a containing element, here I've just used body, but more targeted selectors can give better performance.
You could then check the class of the item clicked.
Example below..
document.body.addEventListener("click", function (evt) {
var el = evt.srcElement;
if (el.classList.contains("box"))
el.classList.toggle("clicked");
});
.clicked {
background-color: yellow;
}
<div class="box">Box 1</div>
<div class="notabox">Not a Box</div>
<div class="box">Box 2</div>

How do I apply jQuery's slideToggle() to $(this) and do the opposite to all other elements?

What I'd like to do is have all elements of class collapsible_list not displayed by default (with one exception... see below*), and then toggle their display when their parent <div class="tab_box"> is clicked. During the same click, I'd also like for every other element of class collapsible_list to be hidden so that only one of them is expanded at any given time.
*Furthermore, when the page initially loads I'd also like to check to see if an element of collapsible_list has a child a element whose class is activelink, and if there is one then I'd like that link's parent collapsible_list element to be the one that's expanded by default.
Here's some sample html code:
<style>
.collapsible_list {
display: none;
}
.collapsible_list.active {
display: block;
}
</style>
<div id="sidebar">
<div class="tab_box">
<div class="collapsible_tab">2014</div>
<div class="collapsible_list panel-2014">
1
2
3
</div>
</div>
<div class="tab_box">
<div class="collapsible_tab">2013</div>
<div class="collapsible_list panel-2013">
<a class="activelink" href="/2013/1">1</a>
2
3
</div>
</div>
</div>
And here's where I'm currently at with the javascript (although I've tried a bunch of different ways and none have worked like I'd like them to):
$(document).ready(function() {
// This looks redundant to me but I'm not sure how else to go about it.
$(".collapsible_list").children("a.activelink").parent(".collapsible_list:not(.active)").addClass("active");
$(".tab_box").click(function() {
$(this).children(".collapsible_list").toggleClass("active").slideToggle("slow", function() {
$(".collapsible_list.active:not(this)").each(function() {
$(this).slideToggle("slow");
});
});
});
});
I hope that's not too confusing, but if it is then feel free to let me know. Any help is much appreciated.
Since you have a dom element reference that needs to be excluded use .not() instead of the :not() selector
jQuery(function ($) {
// This looks redundant to me but I'm not sure how else to go about it.
$(".collapsible_list").children("a.activelink").parent(".collapsible_list:not(.active)").addClass("active").show();
$(".tab_box").click(function () {
var $target = $(this).children(".collapsible_list").toggleClass("active").stop(true).slideToggle("slow");
//slidup others
$(".collapsible_list.active").not($target).stop(true).slideUp("slow").removeClass('active');
});
});
Also, instead of using the slide callback do it directly in the callback so that both the animations can run simultaniously
Also remove the css rule .collapsible_list.active as the display is controlled by animations(slide)
Try This.
$('.collapsible_tab a').on('click', function(e){
e.preventDefault();
$('.collapsible_list').removeClass('active')
$(this).parent().next('.collapsible_list').toggleClass('active');
});
Fiddle Demo
I think your code would be less complicated if you simply remembered the previously opened list:
jQuery(function($) {
// remember current list and make it visible
var $current = $('.collapsible_list:has(.activelink)').show();
$(".tab_box").on('click', function() {
var $previous = $current;
// open new list
$current = $('.collapsible_list', this)
.slideToggle("slow", function() {
// and slide out the previous
$previous.slideToggle('slow');
});
});
});
Demo

JQuery .not(next) - is it possible?

Example HTML:
<div class=blah>
<div class=moreCats></div>
</div>
<div class=subCats>.......</div>
<div class=blah>
<div class=moreCats></div>
</div>
<div class=subCats>.......</div>
<div class=blah>
<div class=moreCats></div>
</div>
<div class=subCats>.......</div>
Using slideToggle, if I click the first div moreCats I want next subCats to slideDown, which it does. At the same time I want to slideUp any other open subCats, but, NOT the one I'm toggling or else it would close then reopen, which is what its doing.
Question: is this valid? If not is there something similar?
$('div.subCats').not($(this).next('.subCats')).slideUp();
Here's the full JQuery I'm trying
// show children cat items
$('#sideNav').on("click", ".moreCats", function() {
$('div.subCats').not($(this).next('.subCats')).slideUp(); // close all except next
$(this).next('.subCats').slideToggle(); // slideToggle next
});
You can combine them by placing the slideToggle for the current target (which will return that element) inside .not and you want to select the parent's next as well
$('#sideNav').on("click", ".moreCats", function() {
$('div.subCats').not($(this).parent().next('.subCats').slideToggle()).slideUp();
//or do $(this).closest('.blah').next('.subCats');
});
Demo
If you want to split them, then better cache the next instead of selecting it again.
$('#sideNav').on("click", ".moreCats", function() {
var $target = $(this).parent().next('.subCats');
$('div.subCats').not($target.slideToggle()).slideUp();
//or just do as below
//$('div.subCats').not($target).slideUp();
//$target.slideToggle()
});
.moreCats doesn't have any siblings so you can't use .next(). What you really need is to get the next sibling of this's parent. So you go from $(this) > .parent() > .next('.subCats')
$('body').on("click", ".moreCats", function() {
console.log($(this).parent().next('.subCats'));
$('div.subCats').not($(this).parent().next('.subCats')).slideUp(); // close all except next
$(this).parent().next('.subCats').slideToggle(); // slideToggle next
});
See this JSFiddle for an example.
What you have is valid but it doesn't do what you expect, .next() selects the next immediate sibling element, you should first select the parent element:
$('div.subCats').not($(this.parentNode).next('.subCats')).slideUp();
You can also use .index() method:
$('#sideNav').on({
click: function() {
var $sub = $('div.subCats'),
i = $('#sideNav .moreCats').index(this);
$sub.not( $sub.eq(i).slideToggle() ).slideUp();
}
}, ".moreCats");

Swap two divs with a same class

I am sort-of stuck with this minor part and I can't move on with my project.
Basically what I am trying to do is to fadeIn/fadeOut between two divs with same class, but keep the function as short as possible.
I have made following but apparently it will work only if both divs are hidden in the begginging and I need to show default title (first div) on load and after 2 seconds I want to swap to another title and then it will keep going circular.
HTML:
<div class="ref-title">Sample Title #1</div>
<div class="ref-title">Sample Title #2</div>
JS:
function titleSwap () {
$('.ref-title:hidden:first').fadeIn(500).delay(2000).fadeOut(500, function () {
$(this).appendTo($(this).parent());
titleSwap();
});
} titleSwap();
CSS:
.ref-title {
display: none;
}
JS Fiddle Demo
So I need first div displayed as block and then it will disappear and the other one will appear and keep going on like that... Any tips ?
JSFiddle - Adding a hidden class to the div you want to start as hidden and then changing the function as below should work.
HTML
<div class="ref-title">Sample Title #1</div>
<div class="ref-title hidden">Sample Title #2</div>
CSS
.hidden {
display: none;
}
JS
(function titleSwap() {
$('.ref-title').not('.hidden').delay(2000).fadeOut(500, function () {
var $me = $(this);
$('.ref-title.hidden').removeClass('.hidden').hide().fadeIn(500, function () {
$(this).removeClass('hidden');
$me.addClass('hidden');
titleSwap();
});
});
})();
Additionally, if you don't want to include the hidden class on the DIV within the mark-up you can just use $('.ref-title:nth-child(2)').addClass('hidden'); before the titleSwap function to add the class to the second DIV.
If you can use just show/hide you can try like this: show/hide Example
function toggleTitle() {
$('header > h2').delay(2000).toggle('fast', function () {
toggleTitle();
});
}
If you must use fadeIn/fadeOut its a bit more complicated due to the concurrent fade effect between the titles... this is my solution fadeIn/Out Example
function toggleTitle() {
var visible = $('header > h2:visible');
var hidden = $('header > h2:hidden');
visible.delay(2000).fadeToggle('fast', function () {
hidden.fadeToggle('fast');
toggleTitle();
});
}
it's easy if you put ID's on them, is this posible? check out this answer
jQuery fadeOut one div, fadeIn another on its place
$('#fadeout').fadeOut(300);
$('#fadein').delay(2000).fadeIn(300);
if you cannot add IDs, try this. it assumes they are the only elements under their immediate parent
$('.ref-title:first-child').fadeOut(300);
$('.ref-title:last-child').delay(2000).fadeIn(300);

How to select one child div by clicking on another child div of the same parent in jQuery?

For example I have simple html.
<body>
<div class="a">
<div class="child"></div> <!-- div element I click -->
<div class="childINeedToSelect"></div> <!-- div element I need to be selected -->
<div class="child"></div>
</div>
<div class="a">
<div class="child"></div>
<div class="childINeedToSelect"></div>
<div class="child"></div>
</div>
</body>
When I click on top first child class div I need to change, for example, border ONLY of the first childINeedToSelect class div. They have the same parent - a class div, but the difficult is that there are more than just one element with class a. I've already tried:
$(document).ready(function () {
var child = $('.child');
child.bind('click', function() {
detectElement($(this));
});
});
var belt;
function detectElement(arrow) {
belt = arrow.parent('.a').children('childINeedToSelect').eq(1);
belt.css("background-color", "red");
}
As you see I'm trying to send $(this) as parameter to detectElement() to determine which div was clicked. But my target div background doesn't change, and when I try to use element belt later, after it was detected by detectElement() function, Opera javascript debugger gives me error
Unhandled Error: Cannot convert 'belt.css('marginLeft')' to object
in line
var currentMargin = parseInt(belt.css('marginLeft').toString().replace('px', ''));
but this line of code worked perfectly, before calling detectElement() function; What am I doing wrong? How should I select element I need?
I'd suggest:
function detectElement(arrow) {
arrow.parent().find('.childINeedToSelect').css('background-color','red');
}
$(document).ready(function(){
$('.child').click(function(){
detectElement($(this));
});
});
JS Fiddle demo.
Or you could use the nextAll() method to find the sibling childINeedToSelect:
function detectElement(arrow) {
arrow.nextAll('.childINeedToSelect').css('background-color','red');
}
JS Fiddle demo.
And if you should have multiple .child and childINeedToSelect elements, you can pass the :first selector into the nextAll() method:
function detectElement(arrow) {
arrow.nextAll('.childINeedToSelect:first').css('background-color','red');
}
JS Fiddle demo.
I'm unsure why you were using bind(), but on the off-chance that you might be trying to account for dynamically-added elements (added after the event-handlers are bound to the various DOM nodes/jQuery objects), you could instead use on():
$('.a').on('click','.child', function(){
detectElement($(this));
});
JS Fiddle demo.
References:
find().
:first selector.
nextAll().
on().
parent().
Try this fiddle
$(document).ready(function () {
var child = $('.child');
child.bind('click', function() {
detectElement($(this));
});
});
var belt;
function detectElement(arrow) {
belt = arrow.siblings('.childINeedToSelect').eq(0);
belt.css("background-color", "red");
}
Try something like
jQuery('.a').children().first().click(function(){
jQuery('.childINeedToSelect').attr('background-color','red');
)}

Categories

Resources