Open/Close Icons - javascript

I'm doing some shennanigans with jQuery to put little plus/minus icons next to my expanders. Its similar to the windows file trees, or firebugs code expanders.
It works, but its not specific enough.
Hopefully this makes sense...
$('div.toggle').hide();//hide all divs that are part of the expand/collapse
$('ul.product-info li a').toggle(function(event){
event.preventDefault();
$(this).next('div').slideToggle(200);//find the next div and sliiiide it
$('img.expander').attr('src','img/content/info-close.gif');//this is the part thats not specific enough!!!
},function(event) { // opposite here
event.preventDefault();
$(this).next('div').slideToggle(200);
$('img.expander').attr('src','img/content/info-open.gif');
});
<ul class="product-info">
<li>
<a class="img-link" href="#"><img class="expander" src="img/content/info-open.gif" alt="Click to exand this section" /> <span>How it compares to the other options</span>
</a>
<div class="toggle"><p>Content viewable when expanded!</p></div>
</li>
</ul>
There are loads of $('img.expander') tags on the page, but I need to be specific. I've tried the next() functionality ( like I've used to find the next div), but it says that its undefined. How can I locate my specific img.expander tag? Thanks.
EDIT, updated code as per Douglas' solution:
$('div.toggle').hide();
$('ul.product-info li a').toggle(function(event){
//$('#faq-copy .answer').hide();
event.preventDefault();
$(this).next('div').slideToggle(200);
$(this).contents('img.expander').attr('src','img/content/info-close.gif');
//alert('on');
},function(event) { // same here
event.preventDefault();
$(this).next('div').slideToggle(200);
$(this).contents('img.expander').attr('src','img/content/info-open.gif');
});

$(this).contents('img.expander')
This is what you want. It will select all of the nodes that are children of your list. In your case, all of your images are nested inside of the list element, so this will filter out only what you want.

How about making your click event toggle a CSS class on a parent item (in your case, perhaps the ul.product-info). Then you can use CSS background properties to change the background image for a <span> instead of using a literal <img> and trying to fiddle with the src. You would also be able to accomplish a showing and hiding on your div.toggle's.
ul.product-info.open span.toggler {
background-image: url( "open-toggler.png" );
}
ul.product-info.closed span.toggler {
background-image: url( "closed-toggler.png" );
}
ul.product-info.open div.toggle {
display: block;
}
ul.product-info.closed div.toggle {
display: hidden;
}
Using jQuery navigation/spidering functions can be slow when the DOM has many items and deep nesting. With CSS, your browser will render and change things more quickly.

Have you tried the .siblings() method?
$(this).siblings('img.expander').attr('src','img/content/info-close.gif');

Related

Show multiple containers with the same class when clicking an item

I have a long page, where one section is tabbed content. However, at the same time as showing tabs, I'd like for other sections further down the page to be visible or hidden, depending on which tab is clicked. Since each tab would display about 4 containers further down the page, I'd like to use classes for this rather than ID's. This is a rough outline of what I have so far (tab content removed, as it's unnecessary):
<div class="horisontal-tabs">
<ul class="tabs">
<li class="tab-label active person-sam" rel="tab1">Sam</li>
<li class="tab-label person-bob" rel="tab2">Bob</li>
<li class="tab-label person-jack" rel="tab3">Jack</li>
<li class="tab-label person-kelly" rel="tab4">Kelly</li>
</ul>
</div>
<div class="container-sam section-visible">Custom content only for Sam</div>
<div class="container-bob section-hidden">Custom content only for Bob</div>
<div class="container-jack section-hidden">Custom content only for Jack</div>
<div class="container-kelly section-hidden">Custom content only for Kelly</div>
<div class="container-sam section-visible">Other content for Sam</div>
<div class="container-bob section-hidden">Other content for Bob</div>
<div class="container-jack section-hidden">Other content for Jack</div>
<div class="container-kelly section-hidden">Other content for Kelly</div>
And I have jquery as per below for each person, but it doesn't seem to be working, and I can't figure out how to simplify it down. The idea is that when you click on one person's tab, all the other people's sections will be hidden and that person's will be visible.
$('.horizontal-tabs ul.tabs li.person-sam').click(function (event) {
$('.container-sam').removeClass('section-hidden').addClass('section-visible');
$('.container-sam.section-visible').removeClass('section-visible').addClass('section-hidden');
event.stopPropagation();
});
I have opted to not use ID on the sections and use a class instead, because multiple will need to show at once, so they wouldn't be unique.
Any tips will be greatly appreciated! :)
So the question is how to make simpler?
What comes to mind is you don't need active and inactive classes, you just need one of them, and then you can make the other be the default state . That is, add a default class .section to all sections and either use .section as the visible state and add .section-hidden to hide it, or use .section as the hidden state and add .section-visible to show it.
Say you go with .section-visible, the css would be something like this:
.section { display: none }
.section.section-visible { display: block }
This would also simplify your javascript because now you can reset all sections and just turn on/off the ones you need.
If you go, again, with .section-visible, run this on click:
$('.section').removeClass('section-visible'); // reset all sections
$('.container-sam').addClass('section-visible'); // add visible class to specific sections
You can see you only need one extra class, not two.
BONUS 1: you can use BEM to make it clearer.
BONUS 2: it looks like you have one click listener for each person, but instead you can use the HTML dataset API and the jQuery .data() function to detect which person's button you're pressing. That way you would have only one click listener, and you can detect which li was clicked by checking the data- attribute. Like <li data-person="sam">sam</li> and const containerSelector = `.container-${$(this).data('person')}`;. $(this) will select the li clicked, and .data('person') will return 'sam'. So the selector will be .container-sam.

Open a sub-menu using jQuery

I have this menu:
What I want to do: when I click the image button on the right (#sub-menu) I want it to open the sub-menu (.sports2).
this is a sub-item html code for an example:
<a href="#"><li> Golf
<img src="strokesmenu.png" id="sub-menu" />
<ul class="sports2">
<li>British Open</li>
<li>Masters</li>
<li>PGA Championship</li>
<li>US Open</li>
</ul>
</li></a>
Why this code isn't working for me?
$('#sub-menu').click(function(){
//$('.sports2').slideToggle("slow");
$(this).find('ul>li').slideToggle(slow);
})
first of all, <li>British Open</li> this structuring is so wrong I cannot even describe it how wrong it is.
convert it to the <li>British Open</li> if you want to make click-able while li try using below css or similar to that
ul li a {
display: inline-block;
width:100%;
height:100%;
}
also there must be only one item with one id having multiple item is against the W3C rules and clicking the little icon is not so user friendly. so instead give class to main item li and hanle the click with that one.
$('li.main').click(function(){
$(this).find('ul').slideToggle('slow');
})
apparently you cannot do that so you have to bind it to the img first change id to the class e.g. class="sub-menu"
$('li img.sub-menu').click(function(){
//$(this) -> img .next() -> ul
$(this).next().slideToggle('slow');
})
now the $(this).find('ul>li').slideToggle('slow'); should work but it will open every li and might cause some problem issues.
instead I suggest using $(this).find('ul').slideToggle('slow'); so the list can be opened/closed. you see the animation differences by trying it and choose the best one for you.
EDIT FOR CLICK BUG:
well not sure if I get it right but as I understand in some cases you need to redirect the page in others open the sub menu.
in that case you can check if the li has submenu or not the following code should do the trick.
$('li.main').click(function(){
if ($(this).has("ul")) // if has submenu
$(this).find('ul>li').slideToggle('slow');
else
// your redirect code.
})

Remove a Div class that inside a parent Div with jQuery

I have a div on top of a image. I want use jQuery click event to remove (or change the div class) the div on image click.
Div structure.
<div class="post">
<img class="thumb" src="MyImg.jpg">
<div class="show-div"></div>
</div>
I want to toggle class show-div to remove-div.
Here is my jQuery
$(document).ready(function(){
$(".thumb").click( function(){
$(this).parent().('.show-div').toggleClass('remove-div');
});
});
I have made remove-div class to display none in the css style sheet. but this doesnt seems to work. Also i have tried
$(this).parent().find('.show-div').toggleClass('remove-div');
Please note that this is a PHP while loop and there will be more then one div at this page.
If someone can point me out the right way to do this it will be most appropriated.
Try this:
$(document).ready(function(){
$(".thumb").click( function(){
$(this).parent().find('div.show-div').removeClass('show-div').addClass('remove-div');
});
});
The code given works http://jsfiddle.net/4WDet
However, you're not removing .show-div, so if that is display: block AND your CSS rules are in this order that is your problem.
.remove-div{
display:none;
}
.show-div{
display:block;
}
In which case, switch your CSS styles around
.show-div{
display:block;
}
.remove-div{
display:none;
}
or toggle both classes
$(this).parent().find('.show-div').toggleClass('remove-div show-div');
But the problem then is that you won't find that div again, so you need to change the selector:
$(this).parent().find('.show-div, .remove-div').toggleClass('remove-div show-div');
Working example
.show-div is not a parent of .thumb, but a sibling. Have you tried?
$(this).siblings('.show-div').toggleClass('remove-div');
Note, that this will return an array if there are more than one .show-div sibling.
$(this).siblings().toggle("slow");
try this

Multiple items with same class, how to distinguish them with jQuery?

I have a dropdown list where there are multiple items with class "dropdown" and "menu". On click event I want javascript to find the certain .dropdown that I clicked. Is it possible to implement "this" somewhere on my code and make it work?
$(".dropdown").click(function(e) {
e.preventDefault();
if ($(".menu").is(":visible")) {
$(".menu").slideUp();
$(this).find("li").children(".list").addClass("plus").removeClass("minus");
} else {
$(".menu").slideDown();
$(this).find("li").children(".list").removeClass("plus").addClass("minus");
}
});
Edited afterwards:
So this is my list (please don't pay attention to the fact that "a" is outside of "li"). So I need to find closest "menu" to "dropdown". Already tried closest, find etc. but nothing I tried did the trick. Any suggestions?
<a class="dropdown" href=""><li>Link 1 <div class="plus"></div></li></a>
<ul class="menu">
....
Within the event handling function, this will be set to the element that was clicked.
If that does not help, you should provide more information in your question.
jQuery uses CSS selectors so just do $(".dropdown > .menu") to select the first .menu following a .dropdown. or $(".dropdown .menu:first-child")
edit:
$(".dropdown").click(function()
{
var theNextMenu = $(this).next(".menu");
}

Hide button conditionally using javascript and css

I need to display conditionally my shopping cart button using Javascript and Css. My goal is to hide the button when no items are present inside the cart.
The code of my button is:
<span id="mycartbutton" style="float: right; clear: both;">
<a class="button"href="$(shopping_cart_url)">Mon panier</a>
</span>
When nothing is present in the cart, the url look simply like this:
/.../mode=show_cart
When one or more items are present, the url look like this:
/.../mode=show_cart&cart_id=10332&first_reservation_id=717
Unfortunately I'm not a coder and I don't have any knowledges of javascript but I suppose is possible to make a check according to rendered url.
Actually I use the follow javascript:
<script type='text/javascript'>
function on_site_form_loaded(event) {
if (event=='product_list')
document.getElementById('mycartbutton').style.display='none';
}
</script>
..this allow me to hide the button on product list as desired BUT even if some items are inside the cart.
Somebody can tell me which conditional code I must use for check if the url contain for example the text "cart_id"? This will mean something is present inside the cart and will let me hide the button.
If your page is set up like this:
<ul id="cart">
<li>Item 1</li>
<li>Item 2</li>
</ul>
<span id="mycartbutton"...>...</span>
Then you could use this CSS:
#cart:empty~#mycartbutton {display:none}
However this will only work if the cart button is a sibling of the cart itself (if there are element in between them, use + instead of ~), and only if the cart's items are first-level children of the cart element.
If this is not possible, you will need to use JavaScript. Basically you can check the number of items at any time, something like document.getElementById('cart').children.length, and use that information to set display:none or display:block on your button.
If the total URL is in a string Url, do a search for stiring "cart_id" and place it in a boolean.
cartIDFound = Url.search("cart_id");
if (cartIdFound){
// ... cart id is found. items are in cart .. do domething
// .. first,show button by setting visibility to visible and showing display
document.getElementById('mycartbutton').style.visibility='visible';
document.getElementById('mycartbutton').style.display='inline';
// ... next, continue
}
else {
// .. cart id wasn't found; no items in cart.. do something different
// first, hide the cart button
document.getElementById('mycartbutton').style.visibility='hidden';
document.getElementById('mycartbutton').style.display='none';
// ... next, continue
}
I finally found a best solution using CSS:
#mycartbutton a.button {
display: none;
}
#mycartbutton a.button[href*=cart_id] {
display: inline-block;
}
Iit is easier and more reliable because I got some conflict using JavaScript in my case.
Use jQuery hide() function
<script type='text/javascript'>
function on_site_form_loaded(event) {
if (event=='product_list')
$("#mycartbutton").hide();
}
</script>
url.indexOf() should work for you. Try this:
<script>
function check(url){
if(url.indexOf("cart_id")>-1){
// cart_id present do something
}
}
</script>

Categories