I'm working on a js script which will show / hide multiple divs based on css class, seemingly pretty simple. I set out to find an example of this and found something close in the article linked below. I used the code in the following link as a starting point.
Show/hide multiple divs using JavaScript
In my modified code (shown below) I am able to hide all (which is errant) and show all (which works correctly. I'm not sure why its not targeting the CSS class "red, green or blue" correctly. If I hard one of the class names in the script it works as expected, so I'm fairly certain I'm having an issue in the way I'm referencing the css targets themselves.
I am able to hide all and show all, yet I'm having difficulty showing only the selected class.
Here is the jsFiddle I'm working with: http://jsfiddle.net/juicycreative/WHpXz/4/
My code is below.
JavaScript
$('.categories li a').click(function () {
$('.marker').hide();
$((this).attr('target')).show();
});
$('#cat-show').click(function () {
$('.marker').show();
});
HTML
<ul class="categories">
<li id="cat-show" class="cat-col1" target="all" >All</li>
<li id="cat-models" class="cat-col1" target="red" >Model Homes</li>
<li id="cat-schools" class="cat-col1" target="blue">Schools</li>
<li id="cat-hospital" class="cat-col1" target="green" >Hospitals</li>
</ul>
<div id="locator">
<div id="overview-00" class="marker models" title="Maracay Homes<br />at Artesian Ranch"></div>
<!--SCHOOLS-->
<div id="overview-01" class="marker red" title="Perry High School">1</div>
<div id="overview-02" class="marker red" title="Payne Jr. High School">2</div>
<div id="overview-03" class="marker blue" title="Hamilton Prep">3</div>
<div id="overview-04" class="marker blue" title="Ryan Elementary">4</div>
<div id="overview-05" class="marker green" title="Chandler Traditional – Freedom">5</div>
</div>
Thanks in advance for any responses.
$((this).attr('target')).show();
This is syntactically incorrect. It should be $($(this).attr('target'))
However that's no good either because this is the anchor element that does not have the target. Use $(this).closest('li').attr('target') (or add the target to the <a>).
This is also semantically incorrect as that would interpolate to $("red") which would try to look for a <red> element.
$("." + $(this).closest('li').attr('target'))
http://jsfiddle.net/WHpXz/5/
You are almost there. This is the line that needs tweaking: $((this).attr('target')).show();
$(this) actually refers to the current anchor tag that was clicked. Since the anchor tag doesn't have the target attribute, you need to go up to the parent.
From there, you can get the target and add the '.' to the color to use as a selector.
var catToShow = $(this).parent().attr('target');
$('.' + catToShow).show();
I've edited your fiddle. Give it a shot.
http://jsfiddle.net/juicycreative/WHpXz/4/
Related
I've spent far too many hours trying to figure this out and as JavaScript is not my primary language and not yet a jQuery guru I've determined I need to ask for help.
In a case where a generated page has a structure where it has a DIV for some odd reason no ID, multiple non-standard data tag attribute tags, but at least standard style CLASS assignment....however...it has been assigned MULTIPLE classes.
Now, just one of those style classes is such that it has a code event associated that I want to neuter and leave all other classes still assigned. What I've tried there (this list is far from complete I have tried many things):
document.getElementsByClassName('Goodclass01')[0].remove('BADCLASS');
document.querySelectorAll('[data-tag-one="["value",
"value"]"]').remove('BADCLASS');
Various jnode calls that all fail due to claims of being unknown
A couple variations of something referred to as the "location hack" none of
which I could get to work but may have very well have been user error.
Safewindow attempt to just replace BADCLASS javascript function all together
but not ideal explained below.
Here is an example of the kind of structure of the target:
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one="["value", "value"]">
</div>
In this example there is a javascript function that fires upon clicking the href link above due to the function being associated with BADCLASS style assignment. So, from lots of searching it seemed like I should be able to grab that DIV by any of the initially assigned classes (since there is unfortunately not a class ID which would make it very easy) but then reassign the list of classes back minus the BADCLASS at page load time. So, by the time the user clicks the link, the BADCLASS has been removed to look like this:
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03"
data-tag-one="["value", "value"]">
</div>
I also read that simply using unsafewindow to replace the BADCLASS javascript function could be possible, so I am open to hearing one of you gurus help with how easy (or hard) that would be. In a case where BADCLASS could be shared function code perhaps called by another element on the page still having that initial class that perhaps we desire to continue to function which is why if it is only a single element that needs to be altered, I would rather just change this one href div.
Hope the explanation makes sense and what is probably a laughable simple example above for the Javascript gurus so forgive me but your help is greatly appreciated and will save more hair pulling! :)
EDIT: This must work above all in Chrome browser!
Remove the class from all elements
If you want to remove the class from all elements that have the class, simply select all of the elements with that class and remove the class from their class lists.
[...document.querySelectorAll('.BADCLASS')]
.forEach(e => e.classList.remove('BADCLASS'));
const elements = [...document.querySelectorAll('.BADCLASS')];
elements.forEach(e => e.classList.remove('BADCLASS'));
console.log(elements);
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one='["value", "value"]'>link</a>
</div>
Using jQuery:
$('.BADCLASS').removeClass('BADCLASS');
const elements = $('.BADCLASS');
elements.removeClass('BADCLASS');
console.log(elements);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one='["value", "value"]'>link</a>
</div>
Remove the class from a subset of elements
If you only want to remove the class from a subset elements, select those elements then from the class from their class lists.
[...document.querySelectorAll('.Goodclass01, .Goodclass02, .Goodclass03')]
.forEach(e => e.classList.remove('BADCLASS'));
const elements = [...document.querySelectorAll('.Goodclass01, .Goodclass02, .Goodclass03')];
elements.forEach(e => e.classList.remove('BADCLASS'));
console.log(elements);
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one='["value", "value"]'>link</a>
link
</div>
Using jQuery:
$('.Goodclass01, .Goodclass02, .Goodclass03').removeClass('BADCLASS');
const elements = $('.Goodclass01, .Goodclass02, .Goodclass03');
elements.removeClass('BADCLASS');
console.log(elements);
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one='["value", "value"]'>link</a>
link
</div>
Run at document idle
The default for the run-at directive is document-idle, but if for some reason that has been changed, either it needs to be document-idle, or you need to otherwise delay execution of the script until the document has loaded.
You could use the run-at directive in the userscript header like so:
// #run-at document-idle
Or attach a load event listener to the window
window.addEventListener('load', function() { /* do stuff */ }, false);
Include jQuery
If you're using one of the jQuery solutions, you will have to include jQuery using the require userscript header directive like so:
// #require https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js
Got it with the help of both of the clear, awesome correct answers below that literally came in within seconds of each other and only a few min after my post, so thanks to both #Tiny and #Damian below!
I'm upvoting both as they both listed the same correct jQuery answers, and Tiny also provided the pure JS.
I am posting the full answer below because without the other steps, with Tamper/Greasemonkey neither will produce the desired results.
First, Tamper/Greasemonkey do not load jQuery by default, so it is just easy as add #require http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js to your current script and also put this.$ = this.jQuery = jQuery.noConflict(true); to avoid any versioning conflicts.
Also, in this case unfortunately I HAD to change my TamperMonkey header to:
// #run-at document-idle
along with the above mentioned:
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js
and begin the script with:
this.$ = this.jQuery = jQuery.noConflict(true);
and finally the primary accepted/best answer in this case of:
$('.Goodclass01').removeClass('BADCLASS');
NOTE: The above #run-at line is required, and since so many (all) of my current Tamper/Greasemonkey scripts are actually set by default to run at START, this is of importance as it means functions like this must be separated to their own scripts to run instead AFTER the page loads (idle). Once this is added, even the above pure JS answer from Tiny did in fact produce the desired result.
As the simplest one-line answer that I was hoping was possible in Javascript, as it is so many other languages in a single line of code. I've used it in the past, but was not aware of this particular removeClass method.
Your question mentions jQuery. Did you want a solution in jQuery?
If so, it's as easy as:
$(".Goodclass01").removeClass("badclass");
Explanation:
jQuery can be referenced as jQuery() or $(). The parameters you can pass are: 1, a Selector statement (like CSS), and 2, context (optional; default is document).
By stating $(".Goodclass01") you are stating, "Give me a jQuery object with all elements that have the class Goodclass01." Then, by using the removeClass() function, you can either pass it no parameters and it would remove all classes, or you can pass it specific classes to remove. In this case, we call .removeClass("badclass") in order to remove the undesired class.
Now, if you need to select only specific elements, such as links that have Goodclass01, you can do:
$("a.GoodClass01").removeClass("badclass");
Or, if you want to select anything that has Goodclass01, but NOT Goodclass02, you can do:
$(".Goodclass01:not(.Goodclass02)").removeClass("badclass");
jQuery is not as intimidating as it looks. Give it a shot!
Edit: I also noticed you were trying to capture a link with maybe a specific property. You can use the [property] syntax to select elements that have a specific property. Most typically, people use $("a[href^=https]") or something to that effect to select all a tags with the property href that begins with ^= the string https.
You could, in your case, use the following...
$("a[data-tag-one]")
... to select all links that have the property data-tag-one.
Note: One thing to keep in mind is that, a jQuery object is different than a pure DOM element. If you have a collection of multiple elements and want to use a pure JavaScript function on one element in particular, you would have to reference it with either [0] or .get(0). Once you do that, you will no longer be able to use jQuery methods until you convert it back to a jQuery object.
But, since jQuery has a whole slew of methods to use to make DOM manipulation easier, you can probably accomplish what you need to using those methods.
Edit: I've included a snippet below so you can see some of the jQuery selectors in action.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<style>
div#main * { background-color: #66ff66; }
div#main .BADCLASS, div#main .BADCLASS * { background-color: #ff8888 !important; }
</style>
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one='["value", "value"]'>All classes and data-tag-one</a><br />
<a href="SOME LINK" class="Goodclass01 BADCLASS" data-tag-one='["value", "value"]'>Goodclass01 and data-tag-one</a><br />
All classes, no data-tag-one<br />
<a href="SOME LINK" class="BADCLASS" data-tag-one='["value", "value"]'>Just BADCLASS and data-tag-one</a><br />
<br />
<table class="Goodclass01 BADCLASS"><tr><td>Here is a table</td></tr><tr><td>with Goodclass01 and BADCLASS</td></tr></table>
</div>
<hr>
<div id="buttons">
$(".Goodclass01").removeClass("BADCLASS");<br />
$("a.Goodclass01").removeClass("BADCLASS");<br />
$(".Goodclass01:not(.Goodclass02)").removeClass("BADCLASS");<br />
$("a[data-tag-one]").removeClass("BADCLASS");<br />
Reset the HTML<br />
</div>
<script>
$("#button1").click(function(){
$(".Goodclass01").removeClass("BADCLASS");
});
$("#button2").click(function(){
$("a.Goodclass01").removeClass("BADCLASS");
});
$("#button3").click(function(){
$(".Goodclass01:not(.Goodclass02)").removeClass("BADCLASS");
});
$("#button4").click(function(){
$("a[data-tag-one]").removeClass("BADCLASS");
});
$("#button5").click(function(){
var str = '<div class="main_content" data-tag-id="12345">Some stuff sits above</div>All classes, no data-tag-one<br /><a href="SOME LINK" class="BADCLASS" data-tag-one=\'["value", "value"]\'>Just BADCLASS and data-tag-one</a><br /><br /><table class="Goodclass01 BADCLASS"><tr><td>Here is a table</td></tr><tr><td>with Goodclass01 and BADCLASS</td></tr></table>';
$("div#main").html(str);
});
</script>
I've spent the past several hours trying to work out a hover effect for 2 separate links on a site I'm working on. The links aren't even remotely related in the HTML, so I'm unable to use CSS (as far as I can see) to achieve the effect. It's nothing more than a simple hover effect to change the color of two separate links on hove, regardless of which one the user hovers over. There are no images at this point, only text - I'm hoping it stays that way (I'm looking at you, graphic designer wife).
The html involves a bootstrap navbar & a link on the home page of a WordPress site, so the architecture is something like this:
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a class="abt" href="#">About</a></li>
<li><a class="prc" href="#">Work</a></li>
<li><a class="exp" href="#">Testimonials</a></li>
<li><a class="ofc" href="#">Locations</a></li>
<li><a class="con" href="#">Contact</a></li>
</ul>
</div>
</div>
</div>
</div>
<section id="content" role="main">
<article id="post-10" class="post-10 page type-page status-publish hentry">
<header class="header">
<h1 class="entry-title">Home</h1> <a class="post-edit-link" href="#post.php?post=10&action=edit">Edit This</a></header>
<section class="entry-content">
<div class="links">
<li><a class="abt" href="#/about/"><span class="pg abt1">
<p>About</p>
<p></span></a></li>
I'd like to focus on the "About" sections for this - I'm pretty sure that I need either jQuery or JS to accomplish what I'm after but I'm a rank beginner in both!
Alright, so you're right. You need jQuery. First of all, what you should do is give the two link tags the same class, let's say foo. Give both link tags the class foo. Then, use jQuery to target them both.
Now, id you want it to change the color permanently on hover, use THIS:
$('.foo').hover(function(){
$('.foo').css('color', 'red');
});
Feel free to change red to whatever color you like. Now, if you want the color to change only while being hovered over, use this:
$('.foo').mouseenter(function(){
$('.foo').css('color', 'red');
});
$('.foo').mouseleave(function(){
$('.foo').css('color', 'black');
});
in the second chunk, change black to whatever the original color is. If you are unfamiliar with how to use JQuery, add the following tag into your code below the CSS stylesheet (if applicable)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
This makes the browser read the jQuery. If you don't have this, the browser can't read the jQuery.
Then, copy and paste either one of the two bits of jQuery into a file, save it as a .js file, and then attach it via <script> tag after the tag listed above. Alternatively, put the jQuery between two script tags as such:
<script type='text/javascript'>
//one of the two blocks of JQuery here
</script>
Put that in your code After the tag that allows you to use jQuery.
EDIT: I received a request for code to make them different colors. The code would look like this:
First of all, you can keep or remove the class. Then assign them separate IDs , say id_1 and id_2. Then, using the first method:
$('#id_1').hover(function(){
$(this).css('color', 'red');
});
$('#id_2').hover(function(){
$(this).css('color', 'red');
});
This would change the color permanent when hovered on. Using the second method to change the color while being hovered on:
$('#id_1').mouseenter(function(){
$(this).css('color', 'red');
});
$('#id_1').mouseleave(function(){
$(this).css('color', 'black');
});
then do the same thing, but switch id_1 for id_2 and change the colors to whatever. The first color is the color being changed to, and the second one the color being set back to the original.
I'm trying to use jQuery's click function to apply a hover state to a selected div, without differentiating the div's in the JavaScript. I'm currently using:
$(document).ready(function(){
$(".project").click(function() {
$("a.expand").removeClass("hovered");
$("a.expand").addClass("hovered");
$(".project_full").hide();
var selected_tab = $(this).find("a").attr("href");
$(selected_tab).fadeIn();
return false;
});
With the HTML:
<div class="project first project_gizmoscoop">
<div class="title">
GizmoScoop!
<div class="date">2012</div>
</div>
<a class="expand" title="(Caption)" href="#project_1">GizmoScoop!</a>
</div>
<div class="project project_sc">
<div class="title">
Striking Code
<div class="date">2011</div>
</div>
<a class="expand" title="(Caption)" href="#project_2">Striking Code</a>
</div>
The .hovered class is applied to the clicked link (specific styles from an external CSS file). However, everything is being chosen. (See http://www.codeisdna.com for an example).
I know what I'm doing wrong (I should be specifying the individual ID's or using HTML5 data attributes), but I'm stuck unnecessarily. I feel like a complete newb right now, that I can't do something this simple (although I've done more advanced stuff).
You simply need to take advantage of jQuery's flexibility (and good programming practice) and reduce your scope accordingly. You're already doing something similar with your variable definition. For example, to target only those a.expand elements inside the instance of .project that's clicked:
$(".project").click(function() {
$(this).find("a.expand").removeClass("hovered");
...
});
$(".expand").click(function() {
$(this).addClass("hovered");
..
});
I am dynamically adding Collapsable elements to a page. Bootstrap uses the "data-target" attribute to specify which element the collapse toggle applies to.
From the docs:
The data-target attribute accepts a css selector
Is there a way to write a selector which specifies the next sibling of the parent element? All of the examples from the docs seem to use selections by ID.
Specifically the HTML looks like:
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-target="#collapseOne">
Generated Title
</a>
</div>
<div id="collapseOne" class="accordion-body collapse in">
<div class="accordion-inner">
Generated Content... this is big and sometimes needs collapsing
</div>
</div>
</div>
I would like to write something like (pseudo code using jquery syntax illegally):
<a class="accordion-toggle" data-toggle="collapse" data-target="$(this).parent().next()">
But I am starting to suspect this may not be possible with CSS selectors.
Right now as a workaround I am generating a new ID (an incrementing number appended to a string) when I create the element.
Is there a nicer approach using a selector? Should I be using some post-creation javascript to set the data-target attribute? Is generating IDs for dynamic content the standard approach?
While it is true that the selector in a data-target attribute is a jQuery selector, the data-api specification for this plugin provides no means of referencing back to this in the scope of execution (see lines 147-153 in bootstrap-collapse.js for its use).
However, I would like to offer another alternative approach, which is to extend the data-api with your own custom toggle specifier. Let's call it collapse-next.
JS (see update note)
$('body').on('click.collapse-next.data-api', '[data-toggle=collapse-next]', function (e) {
var $target = $(this).parent().next()
$target.data('collapse') ? $target.collapse('toggle') : $target.collapse()
})
HTML
<a class="accordion-toggle" data-toggle="collapse-next">
JSFiddle (updated)
Downside here is that it's a rather tightly coupled approach, since the JS presumes a specific structure to the markup.
Note about IE issues
As #slhck pointed out in his answer, IE9 and under apparently fail on the first click when using an earlier revision of my answer. The cause is actually not an IE issue at all, but rather a Bootstrap one. If one invokes .collapse('toggle') on a target whose Carousel object is uninitialized, the toggle() method will be called twice - once during initialization and then again explicitly after initialization. This is definitely a Bootstrap bug and hopefully will get fixed. The only reason it doesn't appear as a problem in Chrome, FF, IE10, etc, is because they all support CSS transitions, and hence when the second call is made it short-circuits because the first one is still active. The updated workaround above merely avoids the double-call problem by checking for initialization first and handling it differently.
#merv's solution didn't work for me in IE9 and below, since the collapsible state wasn't available unless you clicked at each item once. It did work fine in Firefox and Chrome though. So after two clicks, everything would work.
What I did was set a .collapse-next class to the triggering elements, then force their ul siblings to collapse with toggle set to false:
$(".collapse-next").closest('li').each(function(){
if ($(this).hasClass('active')) {
// pop up active menu items
$(this).children("ul").collapse('show');
} else {
// just make it collapsible but don't expand
$(this).children("ul").collapse({ toggle: false });
}
});
This is for actually toggling the menu state:
$('.collapse-next').click(function(e){
e.preventDefault();
$(this).parent().next().collapse('toggle');
});
It seems that using data- attributes is a somewhat more modern and cleaner approach, but for old browsers working with classes and jQuery seems to do the job as well.
No javascript solution or the solution depends on bootstrap's JS already in use, just exploiting the DOM structure-
See the data-target=""...
A hint to avoid bulky solutions and need no ID or extra JS, trick using markup placement-
<button data-toggle="collapse" data-target=".dropdown-toggle:hover + .more-menu" type="button" class="btn btn-primary dropdown-toggle" >
Show More Menu +
</button>
<div class="collapse more-menu">More menu here...</div>
This CSS selection structure will select the desired DOM .dropdown-toggle:hover + .more-menu and there we can apply our desired CSS.
There are more ways to exploit what we have. :hover or :active or so many other ways.
Yes, you can do it easily! 😎
Just add the following code to your scripts and enjoy: 😃
$('body').on('click','[data-toggle="collapse"][data-mytarget^="$("]',function(){
eval($(this).data('mytarget')).collapse('toggle');
});
Now every where in your code you can set the target of collapse by a fully dynamic jQuery command inside data-mytarget.
Now use it like it:
<a data-toggle="collapse" data-mytarget="$(this).parent().next()">Link</a>
or
<a data-toggle="collapse" data-mytarget="$('#TopMenuBar').closest('ul')">Link</a>
or
<a data-toggle="collapse" data-mytarget="[ EACH IDEAl JQUERY CODE OF YOU STARTED WITH $( ]">Link</a>
Demo:
$('body').on('click','[data-toggle="collapse"][data-mytarget^="$("]',function(){
eval($(this).data('mytarget')).collapse('toggle');
});
a{
padding:10px;
cursor:pointer;
margin:20px;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle btn btn-info" data-toggle="collapse" data-mytarget="$(this).parent().next()">Collapse It</a>
</div>
<div id="collapseOne" class="accordion-body collapse ">
<div class="accordion-inner">
Generated Content... this is big and sometimes needs collapsing
</div>
</div>
</div>
I used data-mytarget instead of data-target. If you use data-target it works too but the jQuery library raise an error like this: Uncaught Error: Syntax error, unrecognized expression: $(this).parent().next().
So I defined my different property with data-mytarget name.
I think the best approach would be to do this iterate all accordion-toggle elements and set their data-target attribute dynamically via jquery and after that place the code of accordion mentioned in bootstrap.
Example :
$(function(){
$("a.accordion-toggle").each(function(index) {
$(this).attr("data-target", "#" + $(this).parent().next().attr("id"));
});
// accoridon code
});
Hope this will help
TYPO3 FCE and Bootstrap Accordion
I am having some trouble with this issue too i am using it in TYPO3 for a customer who wants to be able to add an infinite number of elements to the accordion. So I created a Flexible Content Element and mapped the elements.
The idea with that data-toggle="collapse-next" did not work for me as expected as it did not close the open elements. I created a new javascript-function doing that please find the code here. Hopefully someone finds the stuff useful.
Javascript
$(document).on('click.collapse-next.data-api', '[data-toggle=collapse-next]', function (e) {
var $container = $(this).parents(".accordion");
var $opencontainers = $container.find(".in");
var $target = $(this).parent().next();
$target.data('collapse') ? $target.collapse('toggle') : $target.collapse();
$opencontainers.each(function() {$(this).collapse('toggle')});
})
HTML
<html>
<div class="accordion">
<div class="accordion-section">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse-next">
Collapsible Group Item #1
</a>
</div>
<div class="accordion-body collapse">
<div class="accordion-inner">
Anim pariatur cliche...
</div>
</div>
</div>
</div>
</div>
</html>
Here is an approach that avoids needing unique IDs and avoids a specific html structure.
This encloses each instance of the collapse trigger and target in a "section" of html. I like to use class selectors, especially for multiple instances. In this case, it avoids having to create artificial unique IDs.
Borrowing from #merv's excellent answer, I named the data-toggle collapse-section similar to his collapse-next, and added a data-section attribute.
Instead of parent().next(), this looks up for a closest() section name, then down for the given target name. They can be siblings or any other level.
(I have a naming convention using "id..." as a prefix for class names that are used as jquery selectors, to avoid mixing with styling.)
HTML
<div class="accordion-group idCollapseSection">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse-section"
data-section=".idCollapseSection" data-target=".idCollapseTarget">
Generated Title
</a>
</div>
<div>Any other html, at various depths.
<div class="accordion-body collapse in idCollapseTarget">
<div class="accordion-inner">
Generated Content... this is big and sometimes needs collapsing
</div>
</div>
</div>
</div>
JS
//------------------------------
// Bootstrap Collapse.
//------------------------------
// Extend collapse to contain trigger and target within an enclosing section.
$('body').on('click.collapse-section.data-api', '[data-toggle=collapse-section]', function (e) {
var thisTrigger = $(this);
var sectionSelector = thisTrigger.data("section");
var targetSelector = thisTrigger.data("target");
var target = thisTrigger.closest(sectionSelector).find(targetSelector);
target.data('bs.collapse') ? target.collapse('toggle') : target.collapse();
});
I've been having nothing but problems with this script for a simple hide/show gallery of testimonials.
I think the java is somewhat self explanatory...
When the page loads, I tell it to show the first testimonial in the line up (as the css is display:none) and gives it a selected class name. Works fine in across the board.
On click I want it to remove the selected class place it to another, and then hide the first testimonial and pull up a corresponding one. Except all that happens here is the first testimonial disappears (hide) and the selected class is added.
<script type="text/javascript">
$(document).ready(function(){
$(".testimonial:first").show();
$("li.testID:first").addClass("selectedName");
$("li.testID").click(function(){
$("li.testID").removeClass("selectedName");
$(this).addClass("selectedName");
$(".testimonial").hide();
$(this).next(".testimonial").fadeIn("slow");
});
});
</script>
Example of markup
<ul id="testName">
<li class="testID">Persons Name</li>
<blockquote class="testimonial">
<span class="bqStart">“</span>
Testimoinal here
<span class="bqEnd">”</span><br /><br />
<span class="testAuthor"><b>Name</b><a target="_blank" href="#">Website</a> Company</span>
</blockquote>
As a side note this is working fine in FF and Safari
Your help is greatly appreciated.
Thanks.
It's probably not working in IE because it's not valid markup: you can't have a blockquote as a direct child of a UL, so IE probably stores them in some weird place in the DOM tree which means .next doesn't find them. Can you move the blockquote elements into the li?
Is .testimonial the class you have given to your lists? <ul> or <ol>
It seems as if you are trying to get the next testimonial list to show, when infact you are actually getting the next <li> which has a class of .testimonial which I suspect is incorrect as you are using .testID as the class for your list items.
Please try this instead:
$(this).parent().next(".testimonial").fadeIn("slow");