Ich füge einer Seite dynamisch zusammenklappbare Elemente hinzu. Bootstrap verwendet das Attribut "Datenziel", um anzugeben, für welches Element der Umschaltschalter gilt.

Aus den Dokumenten:

The data-target attribute accepts a css selector

Gibt es eine Möglichkeit, einen Selektor zu schreiben, der das nächste Geschwister des übergeordneten Elements angibt? Alle Beispiele aus den Dokumenten scheinen eine Auswahl nach ID zu verwenden.

Insbesondere sieht der HTML-Code folgendermaßen aus:

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

Ich möchte etwas schreiben wie (Pseudocode mit illegaler JQuery-Syntax):

<a class="accordion-toggle" data-toggle="collapse" data-target="$(this).parent().next()">

Aber ich fange an zu vermuten, dass dies mit CSS-Selektoren möglicherweise nicht möglich ist.

Zur Problemumgehung generiere ich gerade eine neue ID (eine an eine Zeichenfolge angehängte inkrementelle Nummer), wenn ich das Element erstelle.

Gibt es einen schöneren Ansatz mit einem Selektor? Sollte ich Javascript nach der Erstellung verwenden, um das Datenzielattribut festzulegen? Ist das Generieren von IDs für dynamische Inhalte der Standardansatz?

36
Soverman 9 Okt. 2012 im 22:05

7 Antworten

Beste Antwort

Zwar ist der Selektor in einem data-target -Attribut ein jQuery-Selektor, doch bietet die Daten-API-Spezifikation für dieses Plugin im Ausführungsbereich keine Möglichkeit, auf this zurückzugreifen (siehe Zeilen 147-153 in bootstrap -apse.js für seine verwenden).

Ich möchte jedoch einen anderen alternativen Ansatz anbieten, nämlich die Erweiterung der Daten-API um Ihren eigenen benutzerdefinierten Umschaltspezifizierer. Nennen wir es Zusammenbruch-Weiter .

(siehe Update-Hinweis)

$('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 (aktualisiert)

Der Nachteil hierbei ist, dass es sich um einen ziemlich eng gekoppelten Ansatz handelt, da der JS eine bestimmte Struktur für das Markup voraussetzt.


Hinweis zu IE-Problemen

Wie @slhck in seiner Antwort hervorhob, scheitern IE9 und darunter anscheinend beim ersten Klick, wenn eine frühere Überarbeitung meiner Antwort verwendet wird . Die Ursache ist eigentlich überhaupt kein IE-Problem, sondern ein Bootstrap-Problem. Wenn man .collapse('toggle') auf einem Ziel aufruft, dessen Carousel Objekt nicht initialisiert ist, wird die toggle() -Methode zweimal aufgerufen - einmal während der Initialisierung und dann erneut explizit nach der Initialisierung. Dies ist definitiv ein Bootstrap-Fehler und wird hoffentlich behoben. Der einzige Grund, warum es in Chrome, FF, IE10 usw. nicht als Problem angezeigt wird, ist, dass alle CSS-Übergänge unterstützen. Wenn also der zweite Aufruf erfolgt, wird der erste kurzgeschlossen einer ist noch aktiv. Die oben beschriebene aktualisierte Problemumgehung vermeidet lediglich das Problem des doppelten Aufrufs, indem zuerst nach der Initialisierung gesucht und anders behandelt wird.

26
Community 23 Mai 2017 im 12:17

Hier ist ein Ansatz, bei dem keine eindeutigen IDs und keine bestimmte HTML-Struktur benötigt werden.

Dies schließt jede Instanz des Kollaps-Triggers und -Ziels in einen "Abschnitt" von HTML ein. Ich verwende gerne Klassenselektoren, insbesondere für mehrere Instanzen. In diesem Fall müssen keine künstlichen eindeutigen IDs erstellt werden.

In Anlehnung an die hervorragende Antwort von @ merv habe ich den Datenumschalter collapse-section ähnlich seinem collapse-next benannt und ein Datenabschnittattribut hinzugefügt. Anstelle von parent (). Next () wird nach dem Namen des nächsten () Abschnitts gesucht und dann nach dem angegebenen Zielnamen. Sie können Geschwister oder jede andere Ebene sein.

(Ich habe eine Namenskonvention, bei der "id ..." als Präfix für Klassennamen verwendet wird, die als JQuery-Selektoren verwendet werden, um ein Vermischen mit dem Styling zu vermeiden.)

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();
});
0
goodeye 3 Sept. 2017 im 02:47

Die Lösung von @ merv funktionierte in IE9 und darunter nicht für mich, da der zusammenklappbare Status nur verfügbar war, wenn Sie einmal auf jedes Element geklickt haben. In Firefox und Chrome hat es allerdings gut funktioniert. Nach zwei Klicks würde also alles funktionieren.

Ich habe eine .collapse-next Klasse auf die auslösenden Elemente gesetzt und dann ihre ul Geschwister zum Kollabieren gezwungen, wobei toggle auf false gesetzt ist:

$(".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 });
  }
});

Dies dient zum tatsächlichen Umschalten des Menüstatus:

$('.collapse-next').click(function(e){
  e.preventDefault();
  $(this).parent().next().collapse('toggle');
});

Es scheint, dass die Verwendung von data- -Attributen ein etwas modernerer und sauberer Ansatz ist, aber für alte Browser, die mit Klassen und jQuery arbeiten, scheint dies ebenfalls zu funktionieren.

4
slhck 21 März 2013 im 14:59

Ja, das geht ganz einfach! 😎

Fügen Sie einfach den folgenden Code zu Ihren Skripten hinzu und genießen Sie: 😃

$('body').on('click','[data-toggle="collapse"][data-mytarget^="$("]',function(){
     eval($(this).data('mytarget')).collapse('toggle');
});

Jetzt können Sie überall in Ihrem Code das Ziel des Zusammenbruchs mit einem volldynamischen jQuery-Befehl in data-mytarget festlegen.

Verwenden Sie es jetzt wie folgt:

<a data-toggle="collapse" data-mytarget="$(this).parent().next()">Link</a>

Oder

<a data-toggle="collapse" data-mytarget="$('#TopMenuBar').closest('ul')">Link</a>

Oder

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

Ich habe data-mytarget anstelle von data-target verwendet. Wenn Sie data-target verwenden, funktioniert es auch, aber die jQuery-Bibliothek löst einen Fehler wie den folgenden aus: Uncaught Error: Syntax error, unrecognized expression: $(this).parent().next().

Also habe ich meine andere Eigenschaft mit dem Namen data-mytarget definiert.

2
RAM 30 Juni 2017 im 12:04

Ich denke, der beste Ansatz wäre, alle accordion-toggle Elemente zu iterieren und ihr data-target -Attribut dynamisch über jquery zu setzen und danach den im Bootstrap erwähnten Akkordeoncode zu platzieren.

Beispiel:

$(function(){
    $("a.accordion-toggle").each(function(index) {
        $(this).attr("data-target", "#" + $(this).parent().next().attr("id"));
    });

    // accoridon code
});

Hoffe das wird helfen

1
Kundan Singh Chouhan 9 Okt. 2012 im 18:22

Keine Javascript-Lösung oder es hängt von den bereits verwendeten js des Bootstraps ab, wobei nur die DOM-Struktur ausgenutzt wird.

Siehe die data-target="" ...

Ein Hinweis für eine einfache Möglichkeit, die sperrigen Lösungen zu reduzieren.

<button
data-toggle="collapse"
data-target=".dropdown-toggle:hover + .more-menu"
type="button"
class="btn btn-primary dropdown-toggle"
>
  Toggle Bagal Wala
</button>
<div class="collapse more-menu">I will be toggled</div>

Diese CSS-Auswahlstruktur wählt das gewünschte DOM .dropdown-toggle:hover + .more-menu aus und dort können wir unser gewünschtes CSS anwenden. Es gibt mehr Möglichkeiten, das auszunutzen, was wir haben. :hover oder :active oder so viele andere Möglichkeiten.

2
Vishal Kumar Sahu 20 Aug. 2018 im 20:55

TYPO3 FCE und Bootstrap Akkordeon

Ich habe auch Probleme mit diesem Problem. Ich verwende es in TYPO3 für einen Kunden, der dem Akkordeon eine unendliche Anzahl von Elementen hinzufügen möchte. Also habe ich ein flexibles Inhaltselement erstellt und die Elemente zugeordnet.

Die Idee mit diesem Daten-Toggle = "Zusammenbruch-Weiter" funktionierte bei mir nicht wie erwartet, da die offenen Elemente nicht geschlossen wurden. Ich habe eine neue Javascript-Funktion erstellt, die den Code hier findet. Hoffentlich findet jemand das Zeug nützlich.

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>
0
Thomas 6 Aug. 2013 im 10:50