Why jquery toggleClass() only works in even siblings? - javascript

I have DOM like this in a Rails app:
<div class="post_info">
<div class="col">
<i class="post_comments">icon</i>
</div>
</div>
<div class="comments_body">
<ul>
<li>Many comments.</li>
</ul>
</div>
My target is hide and show '.comments_body' element right below the '.post_comment' icon which I clicked.
I've tried this:
css
.comments_body {
display: none;
}
.active {
display: block;
}
What I was trying to is target the icon's 'grandparent's next sibling', means the comments_body relating to this icon, then toggle it's display style.
my jquery code:
<script>
$(".post_info").click(function(event) {
$(event.target).parent().parent().next().toggleClass('active');
});
</script>
But it turns out this only works on even comments_body like the 2nd ,4th ,6th ,8th.
I checked dev tool, when I click on odd icon, the event wasn't be triggered.
How to solve this? Or is there better way to achieve this effect?
Update:
I tried the answers below but still not work. I put the page's github address here. Since it's a Rails app, you might need to clone it to local and try it. If so, run seed to generate fake data. Thanks!

First, you need to remove the : from this:
.comments_body: { /* <==== Remove that : */
display: none;
}
Then, this within your event handler is the .post_info element, so you can use that instead of $(e.target).parent().parent() which is inherently fragile (both because a small change to your markup breaks it, and because if you click within the .post_info but outside the icon, it will be wrong — which I suspect is why you're seeing the inconsistent behavior).
$(".post_info").click(function(event) {
$(this).next().toggleClass('active');
});
Live Example:
$(".post_info").click(function(event) {
$(this).next().toggleClass('active');
});
.comments_body {
display: none;
}
.active {
display: block;
}
<div class="post_info">
<div class="col">
<i class="post_comments">icon 1</i>
</div>
</div>
<div class="comments_body">
<ul>
<li>Many comments 1.</li>
</ul>
</div>
<div class="post_info">
<div class="col">
<i class="post_comments">icon 2</i>
</div>
</div>
<div class="comments_body">
<ul>
<li>Many comments 2.</li>
</ul>
</div>
<div class="post_info">
<div class="col">
<i class="post_comments">icon 3</i>
</div>
</div>
<div class="comments_body">
<ul>
<li>Many comments 3.</li>
</ul>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Side note: You might consider using event delegation for that handler rather than hooking the event on each individual .post_info. That way, if you add and remove .post_info instances at runtime, the handler will keep working.
Presumably these are in some kind of container, so you'd use:
$("selector-for-the-container").on("click", ".post_info", function(event) {
$(this).next().toggleClass('active');
});
Live Example:
$("#container").on("click", ".post_info", function(event) {
$(this).next().toggleClass('active');
});
// Works on #4 even though we add it later:
setTimeout(function() {
$("#container").append(
'<div class="post_info">' +
'<div class="col">' +
'<i class="post_comments">icon 4</i>' +
'</div>' +
'</div>' +
'<div class="comments_body">' +
'<ul>' +
'<li>Many comments 4.</li>' +
'</ul>' +
'</div>'
);
}, 800);
.comments_body {
display: none;
}
.active {
display: block;
}
<div id="container">
<div class="post_info">
<div class="col">
<i class="post_comments">icon 1</i>
</div>
</div>
<div class="comments_body">
<ul>
<li>Many comments 1.</li>
</ul>
</div>
<div class="post_info">
<div class="col">
<i class="post_comments">icon 2</i>
</div>
</div>
<div class="comments_body">
<ul>
<li>Many comments 2.</li>
</ul>
</div>
<div class="post_info">
<div class="col">
<i class="post_comments">icon 3</i>
</div>
</div>
<div class="comments_body">
<ul>
<li>Many comments 3.</li>
</ul>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

$(".post_info").click(function(event) {
$(event.target).parent().parent().next().toggleClass('active');
});
.comments_body {
display: none;
}
.active {
display: block !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="post_info">
<div class="col">
<i class="post_comments">icon</i>
</div>
</div>
<div class="comments_body">
<ul>
<li>Many comments.</li>
</ul>
</div>
<div class="post_info">
<div class="col">
<i class="post_comments">icon</i>
</div>
</div>
<div class="comments_body">
<ul>
<li>Many comments.</li>
</ul>
</div>
<div class="post_info">
<div class="col">
<i class="post_comments">icon</i>
</div>
</div>
<div class="comments_body">
<ul>
<li>Many comments.</li>
</ul>
</div>
I have made a example for you. It working fine. I dont see any problem in case of even odd selection. try making important your active element as
.active {
display: block !important;
}
if it still not creating desired result kindly let me know. I will put my code here. Cheers....

Related

Change class active on click menu list

I'm trying to change the activeTest class of section tag on click, and remove the class that from the section he was, and put on the section I expect to;
I tried the parent() and sibling().
$(document).ready(function() {
$("#test123 .links").click(function(e) {
if (!$(".conteudo-projetoPesquisa").hasClass('active')) {
$(".conteudo-projetoPesquisa.active").removeClass("active");
$(".conteudo-projetoPesquisa.active").siblings().addClass("active");
}
});
});
.conteudo-projetoPesquisa {
display: none;
}
.conteudo-projetoPesquisa.active {
display: block !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="test123" class="row center-xs around-md">
<li class="col-xs-12 col-md-4">
institucional
</li>
<li class="col-xs-12 col-md-4 maioresMelhor">
Maiores e Melhores
</li>
<li class="col-xs-12 col-md-4 faleConosco">
Fale Conosco
</li>
</ul>
<section class="conteudo-projetoPesquisa container active">1
</section>
<section class="conteudo-projetoPesquisa container">2
</section>
<section class="conteudo-projetoPesquisa container">3
</section>
Using Your Code
If your order of links is always the same as the sections you can use the index of the clicked link to determine which section to make visible.
Using index on $("#test123 .links") allows you to query for the index of the clicked link.
Using eq on the collection of $(".conteudo-projetoPesquisa") using the previously determined index will select the section in the same index the clicked link is in.
$(document).ready(function() {
$("#test123 .links").click(function(e) {
var index = $("#test123 .links").index(this);
$(".conteudo-projetoPesquisa").removeClass('active');
$(".conteudo-projetoPesquisa").eq(index).addClass('active');
});
});
.conteudo-projetoPesquisa {
display: none;
}
.conteudo-projetoPesquisa.active {
display: block !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="test123" class="row center-xs around-md">
<li class="col-xs-12 col-md-4">
institucional
</li>
<li class="col-xs-12 col-md-4 maioresMelhor">
Maiores e Melhores
</li>
<li class="col-xs-12 col-md-4 faleConosco">
Fale Conosco
</li>
</ul>
<section class="conteudo-projetoPesquisa container active">1
</section>
<section class="conteudo-projetoPesquisa container">2
</section>
<section class="conteudo-projetoPesquisa container">3
</section>
Alternative using Data Attributes
However, if you have any control over it, it would be better to "pair" the elements. If you for example can populate a data attribute to assign the matching section number to the link itself than the order is not important.
<a href="#!" class="links" data-section-id="1">...
<a href="#!" class="links" data-section-id="2">...
Then you can assign the same value to each section and therefore "pair" the elements.
<section class="conteudo-projetoPesquisa container active" data-section-id="1">...
<section class="conteudo-projetoPesquisa container active" data-section-id="2">...
Then you can use the following code:
$(document).ready(function() {
$("#test123 .links").click(function(e) {
var sectionId = $(this).data('sectionId');
$(".conteudo-projetoPesquisa").removeClass('active');
$(".conteudo-projetoPesquisa[data-section-id=" + sectionId + "]").addClass('active');
});
});
.conteudo-projetoPesquisa {
display: none;
}
.conteudo-projetoPesquisa.active {
display: block !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="test123" class="row center-xs around-md">
<li class="col-xs-12 col-md-4">
institucional
</li>
<li class="col-xs-12 col-md-4 maioresMelhor">
Maiores e Melhores
</li>
<li class="col-xs-12 col-md-4 faleConosco">
Fale Conosco
</li>
</ul>
<section class="conteudo-projetoPesquisa container active" data-section-id="1">1
</section>
<section class="conteudo-projetoPesquisa container" data-section-id="2">2
</section>
<section class="conteudo-projetoPesquisa container" data-section-id="3">3
</section>
To connect links and tabs you should use data-attr
Something like this
$('[data-tab-trigger]').click(function(){
if($(this).is('.active')){
return false;
}
var $wrap = $(this).parents('.tab-wrap');
$('[data-tab-trigger]',$wrap).removeClass('active');
$(this,$wrap).addClass('active');
$('[data-tab-section]',$wrap).removeClass('active');
$('[data-tab-section="'+$(this).data('tab-trigger')+'"]',$wrap).addClass('active');
})
.hide-tab{
display:none;
padding:20px;
background:#333;
color:#fff;
}
.hide-tab.active{
display:block;
}
.tab-wrap{
margin:20px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tab-wrap">
<div data-tab-trigger="1">show first tab</div>
<div data-tab-trigger="2">show second tab</div>
<div class="hide-tab" data-tab-section="2">
second tab
</div>
<div class="hide-tab" data-tab-section="1">
first tab
</div>
</div>
<div class="tab-wrap">
<div data-tab-trigger="1">show first tab</div>
<div data-tab-trigger="2">show second tab</div>
<div class="hide-tab" data-tab-section="2">
second tab
</div>
<div class="hide-tab" data-tab-section="1">
first tab
</div>
</div>

scroll to top using href id

I want to scroll the div to top position.I have problem with get the href value.now 'a' returns undefined in console.log(a);
function myFunction()
{
var a=$(this).attr('href');
console.log(a);
$('html, body').animate({scrollTop: $('#'+a).offset().top-40}, 500);
}
#consulting,#segments,#partner,#insights{min-height:100vh;}
.secMenu{position:fixed;
}
<div class="container-fluid">
<div class="row secMenu">
<div class="col-md-9 col-sm-12 menu">
<ul class="nav navMenu">
<li class="test1">Consulting & Solutions</li>
<li class="test2">Segments</li>
<li class="test3">Our Partners</li>
<li class="test4">Perspectives</li>
</ul>
</div>
</div> <!--End of second menu -->
<div class="row">
<div id="consulting">
div1
</div>
<div id="segments">
div11
</div>
<div id="partner">
div111
</div>
<div id="insights">
div1111
</div>
</div>
</div>
I've made an alternative to what you used, but it does the same thing. I removed the function you used and used jQuery instead. Hope my answer works for you:
$('.nav li a').on('click', function(e) {
e.preventDefault();
var a = $(this).attr('href');
$('html, body').animate({
scrollTop: $(a).offset().top
}, 500);
});
#consulting,
#segments,
#partner,
#insights {
min-height: 100vh;
}
.secMenu {
position: fixed;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container-fluid">
<div class="row secMenu">
<div class="col-md-9 col-sm-12 menu">
<ul class="nav navMenu">
<li class="test1">Consulting & Solutions
</li>
<li class="test2">Segments
</li>
<li class="test3">Our Partners
</li>
<li class="test4">Perspectives
</li>
</ul>
</div>
</div>
<!--End of second menu -->
<div class="row">
<div id="consulting">
div1
</div>
<div id="segments">
div11
</div>
<div id="partner">
div111
</div>
<div id="insights">
div1111
</div>
</div>
</div>
To see it in action you can hit the Run code snippet button above or you can see a fiddle here.
Because this is bind to the global object by default (in browser it's window).
You can try pass this to myFunction() like this: myFunction(this). And in myFunction definition: function myFunction(target) {...}, target now refers to the anchor element.

Hide/Show div not working

Note questions that have already been posted does not solves my problem. The above are the displays from my side menu bar, I want when the user click on a link its content are displayed on the same page and the other div content are hidden. I tried the codes below but they seem not working.
$('a.common').click(function() {
var id = $(this).attr('href');
$(id).fadeIn('slow', function() {
// Animation complete
});
});
<div id="container">
<div id="canvas">
<div id="nav">
<h2 id="title">
<i class="fa fa-sitemap">
</i> MENU</h2>
<ul id="toggle">
<li>
<div class="active border">
HOME
</div>
</li>
<li>
<div>
<span class="menu-icons fa fa-user"></span>
ABOUT US
</div>
</li>
<li>
<div>
PORTFOLIO
</li>
<li>
<div>
CONTACT
</div>
</li>
</ul>
</div>
<i class="fa fa-bars"></i>
<div id="div1">TEST ONE</div>
<div id="div2">TEST TWO</div>
<div id="div3">TEST THREE</div>
</div>
</div>
The problem was that you had $('a.button') instead of $('a.common')
You also want a css to hide the divs at the beginning.
And also when you fade in a new div, you need to hide the current one.
$('a.common').click(function() {
var id = $(this).attr('href');
$("#divs div").hide();
$(id).fadeIn('slow', function() {
// Animation complete
});
});
#divs div {display:none}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="canvas">
<div id="nav">
<h2 id="title">
<i class="fa fa-sitemap">
</i> MENU</h2>
<ul id="toggle">
<li>
<div class="active border">
HOME
</div>
</li>
<li>
<div>
<span class="menu-icons fa fa-user"></span>
ABOUT US
</div>
</li>
<li>
<div>
PORTFOLIO
</div>
</li>
<li>
<div>
CONTACT
</div>
</li>
</ul>
</div>
<i class="fa fa-bars"></i>
<div id="divs">
<div id="div1">TEST ONE</div>
<div id="div2">TEST TWO</div>
<div id="div3">TEST THREE</div>
</div>
</div>
</div>
The problem is in your jQuery selector:
//This ona means that you are searching for tag a with class button
$('a.abutton').click(function() {})
//You should use:
$('a.common').click(function() {})
// Because your a tags has class 'common'
There was 2 problem
Your <div> tag is not closed properly in your <li>
Initially you are not hiding your div so it can be fade in once you click on it.
Here is the fiddle for your code https://jsfiddle.net/2tkfq87o/
First thing is that your html had an error. On <div> element was not added. Secondly you never called hide() on all the divs at the start because of which none of them were hidden. You had only fadeIn. If all divs are visible, it makes no sense to call fadeIn.
So hide them first. Then call fadeIn on click and at the same time hide the div present already.
$(document).ready(function() {
$('a.common').click(function() {
hideAllDivs();
var id = $(this).attr('href');
$(id).fadeIn('slow', function() {
// Animation complete
});
});
var hideAllDivs = function() {
$('#div1').hide();
$('#div2').hide();
$('#div3').hide();
}
hideAllDivs();
$('#div1').show();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="canvas">
<div id="nav">
<h2 id="title">
<i class="fa fa-sitemap">
</i> MENU</h2>
<ul id="toggle">
<li>
<div class="active border">
HOME
</div>
</li>
<li>
<div>
<span class="menu-icons fa fa-user"></span>
ABOUT US
</div>
</li>
<li>
<div>
PORTFOLIO
</div>
</li>
<li>
<div>
CONTACT
</div>
</li>
</ul>
</div>
<i class="fa fa-bars"></i>
<div id="div1">TEST ONE</div>
<div id="div2">TEST TWO</div>
<div id="div3">TEST THREE</div>
</div>
</div>

jquery toggle only one item

i try to add jQuery script that will toggle my footer columns, my problem is how I can make to stop toggling all items. Now when someone click on H4 tags all H4 tags are toggle together.
HTML:
<div class="row footer-cols">
<div class="col-sm-7 five-three">
<div class="row">
<div class="col-sm-4">
<h4>Information<span class="toggle"></span></h4>
<div class="footer-cols-content">
<ul>
<li>About Us</li>
<li>Customer Service</li>
<li>Privacy Policy</li>
</ul>
</div>
</div>
<div class="col-sm-4">
<h4>Why buy from us<span class="toggle"></span></h4>
<div class="footer-cols-content">
<ul>
<li>Shipping & Returns</li>
<li>Secure Shopping</li>
<li>International Shipping</li>
</ul>
</div>
</div>
</div>
</div>
</div>
jQuery SCRIPT
jQuery('.footer .footer-cols h4').append('<span class="toggle"></span>');
jQuery('.footer h4').on("click", function(){
if (jQuery(this).find('span').attr('class') == 'toggle opened') { jQuery(this).find('span').removeClass('opened').parents('.footer-cols').find('.footer-cols-content').slideToggle(); }
else {
jQuery(this).find('span').addClass('opened').parents('.footer-cols').find('.footer-cols-content').slideToggle();
}
});
You could also try the following code:
jQuery('.footer .footer-cols h4').append('<span class="toggle"></span>');
jQuery('.footer-cols h4').on("click", function(){
if (jQuery(this).find('span').attr('class') == 'toggle opened') { jQuery(this).find('span').removeClass('opened').parent().next().slideToggle();
}
else {
jQuery(this).find('span').addClass('opened').parent().next().slideToggle();
}
});
The problem with your selector is that with
parents('.footer-cols')
You basically select
<div class="row footer-cols"></div>
element on top. Thus
find('.footer-cols-content')
selects all child elements in it resulting all of them to slideToggle()
on the click handler change .parents('.footer-cols') for .parents('.col-sm-4')
You will need to add content to the span to give the user something to click
This one changes the plus/minus and hides other content
$(function() {
$(".footer-cols").find("h4").on("click", function() {
var $content = $(this).parent().find(".footer-cols-content");
var $span = $(this).find("span");
if ($span.length==0) $(this).append('<span class="toggle" />');
$(".footer-cols-content").not($content).hide();
$content.slideToggle();
$span.text($span.text() == "-" ? "+" : "-");
});
});
To add the span on the fly:
if ($span.length==0) {
$span=$('<span class="toggle" />');
$(this).append($span);
}
$(function() {
$(".footer-cols").find("h4").on("click", function() {
var $content = $(this).parent().find(".footer-cols-content");
var $span = $(this).find("span");
if ($span.length==0) {
$span=$('<span class="toggle" />');
$(this).append($span);
}
$(".footer-cols-content").not($content).hide();
$content.slideToggle();
$span.text($span.text() == "-" ? "+" : "-");
});
});
.footer-cols-content {
display: none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="row footer-cols">
<div class="col-sm-7 five-three">
<div class="row">
<div class="col-sm-4">
<h4>Information </h4>
<div class="footer-cols-content">
<ul>
<li>About Us
</li>
<li>Customer Service
</li>
<li>Privacy Policy
</li>
</ul>
</div>
</div>
<div class="col-sm-4">
<h4>Why buy from us <span class="toggle">+</span></h4>
<div class="footer-cols-content">
<ul>
<li>Shipping & Returns
</li>
<li>Secure Shopping
</li>
<li>International Shipping
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
I am not sure why are you appending span class but If I am not worng only slide toggle should do the work that you intend to do.
jQuery('.footer-cols h4').on("click", function(){
$(this).find('span').toggleClass('opened').end().next().slideToggle();
});
jQuery('.footer-cols h4').on("click", function(){
$(this).find('span').toggleClass('opened').end().next().slideToggle();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row footer-cols">
<div class="col-sm-7 five-three">
<div class="row">
<div class="col-sm-4">
<h4>Information<span class="toggle"></span></h4>
<div class="footer-cols-content">
<ul>
<li>About Us</li>
<li>Customer Service</li>
<li>Privacy Policy</li>
</ul>
</div>
</div>
<div class="col-sm-4">
<h4>Why buy from us<span class="toggle"></span></h4>
<div class="footer-cols-content">
<ul>
<li>Shipping & Returns</li>
<li>Secure Shopping</li>
<li>International Shipping</li>
</ul>
</div>
</div>
</div>
</div>
</div>
The above code will work only when the footer-cols-content div is always next to h4. To avoid as such you can use parent().
jQuery('.footer h4').on("click", function(){
$(this).parent().find('footer-cols-content').slideToggle();
});

Manipulating first child inside DIV as an UL element in jQuery

Currently I have the below HTML elements.
<div class="ow_box_empty ow_stdmargin clearfix">
<div id="avatar-console" class="ow_avatar_console ow_center">
<div style="height: 190px; background: url(7.jpg) no-repeat;>
<div style="display: none;" id="avatar-change">
Change Avatar
</div>
</div>
<div class="user_online_wrap">
<div class="ow_miniic_live"><span class="ow_live_on"></span></div>
</div>
</div>
</div>
I want to wrap the first DIV(inside DIV with id "avatar-console") with an LI tag and insert new LI tag at the end as shown below.
Below is the required ouput.
<div class="ow_box_empty ow_stdmargin clearfix">
<div id="avatar-console" class="ow_avatar_console ow_center">
<ul>
<li>
<div style="height: 190px; background: url(7.jpg) no-repeat">
<div style="display: none;" id="avatar-change">
Change Avatar
</div>
</div>
</li>
<li class="star">★</li>
</ul>
<div class="user_online_wrap">
<div class="ow_miniic_live"><span class="ow_live_on"></span></div>
</div>
</div>
</div>
I tried the below code to start with but it gives unwanted results. I am not sure where and how to start on this.
$("#avatar-console div:first-child").append('<li class="star">★</li>')
Fiddle Link: http://jsfiddle.net/Purus/U3KC8/
This should work:
http://jsfiddle.net/da4dz/
$("#avatar-console > div:first")
.wrap('<ul><li></li></ul>')
.closest('ul').append('<li class="star">star</li>');
You can use the jQuery wrap() method:
$("div:first-child", "#avatar-console").wrap("<ul><li></li></ul>");

Categories