Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you specify a "data-target" for Bootstrap which refers to a sibling DOM element without using an ID?

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?

like image 365
Soverman Avatar asked Oct 09 '12 18:10

Soverman


People also ask

What is the use of data-target in bootstrap?

data-target is used by bootstrap to make your life easier. You (mostly) do not need to write a single line of Javascript to use their pre-made JavaScript components. The data-target attribute should contain a CSS selector that points to the HTML Element that will be changed.

What is data toggle and data-target in bootstrap?

Just add data-toggle="collapse" and a data-target to element to automatically assign control of a collapsible element. The data-target attribute accepts a CSS selector to apply the collapse to. Be sure to add the class collapse to the collapsible element. If you'd like it to default open, add the additional class in.


2 Answers

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.

like image 69
merv Avatar answered Oct 02 '22 13:10

merv


@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.

like image 32
slhck Avatar answered Oct 02 '22 12:10

slhck