Ich muss in der Lage sein, <select>
Elemente dynamisch zu erstellen und in jQuery umzuwandeln .combobox()
. Dies sollte ein Elementerstellungsereignis sein, im Gegensatz zu einem "Klick" -Ereignis. In diesem Fall könnte ich nur jQuery verwenden .on()
.
Gibt es so etwas?
$(document).on("create", "select", function() {
$(this).combobox();
}
Ich verwende Livequery nur ungern, da es sehr veraltet ist.
UPDATE Die erwähnte Select / Combobox wird über Ajax in eine jQuery Colorbox (Modal Window) geladen, daher das Problem - ich kann Combobox nur mit Colorbox initiieren onComplete
, aber beim Wechsel einer Combobox muss dynamisch eine andere Select / Combobox erstellt werden, dafür brauche ich eine allgemeinere Methode zum Erkennen der Erstellung eines Elements ( select
in diesem Fall).
UPDATE2 Um zu versuchen, das Problem weiter zu erklären - Ich habe select/combobox
Elemente rekursiv erstellt, es enthält auch viel Initiierungscode. .combobox()
Wenn ich also einen klassischen Ansatz wie in der Antwort von @ bipen verwenden würde, würde sich mein Code auf ein wahnsinniges Niveau aufblasen. Hoffe das erklärt das Problem besser.
UPDATE3 Vielen Dank an alle, ich verstehe jetzt, dass die DOMNodeInserted
DOM-Mutation eine Lücke aufweist und es keine Lösung für dieses Problem gibt. Ich muss nur meine Bewerbung überdenken.
quelle
$(select).ready(function() { });
ready
wird verwendet, um: "Eine Funktion anzugeben , die ausgeführt werden soll, wenn das DOM vollständig geladen ist." (von jquery.com)combobox()
Methode beim Erstellen / Einfügen und nicht danach anwenden ?$(document).on('onComplete', 'select', function(){ // bind here? });
? (Verwenden Sie natürlich einen engeren Elternteil als dendocument
.)Antworten:
Sie können
on
dasDOMNodeInserted
Ereignis festlegen, um ein Ereignis abzurufen, wenn es durch Ihren Code zum Dokument hinzugefügt wird.$('body').on('DOMNodeInserted', 'select', function () { //$(this).combobox(); }); $('<select>').appendTo('body'); $('<select>').appendTo('body');
Hier herumgespielt: http://jsfiddle.net/Codesleuth/qLAB2/3/
BEARBEITEN: Nachdem ich herumgelesen habe, muss ich nur noch einmal überprüfen, ob
DOMNodeInserted
es keine Probleme zwischen den Browsern gibt. Diese Frage aus dem Jahr 2010 deutet darauf hin, dass der IE das Ereignis nicht unterstützt. Testen Sie es daher, wenn Sie können.Siehe hier: [Link] Warnung! Der Ereignistyp DOMNodeInserted ist in dieser Spezifikation zur Bezugnahme und Vollständigkeit definiert, diese Spezifikation veraltet jedoch die Verwendung dieses Ereignistyps.
quelle
.delegate
veraltet von jQuery Version 1.7 und ersetzt durch.on
?DOMNodeInserted
sie jetzt veraltet ist.on('DOMNodeInserted'
bevor ich diese Frage gestellt habe. Es hat offensichtlich nicht funktioniert.Sie können einDOMNodeInserted
Mutationsereignis verwenden (keine Delegierung erforderlich):$('body').on('DOMNodeInserted', function(e) { var target = e.target; //inserted element; });
BEARBEITEN: Mutationsereignisse sind veraltet . Verwenden Sie stattdessen den Mutationsbeobachter
quelle
Wie in mehreren anderen Antworten erwähnt, sind Mutationsereignisse veraltet, daher sollten Sie stattdessen MutationObserver verwenden. Da noch niemand Details dazu angegeben hat, geht es los ...
Grundlegende JavaScript-API
Die API für MutationObserver ist ziemlich einfach. Es ist nicht ganz so einfach wie die Mutationsereignisse, aber es ist immer noch in Ordnung.
function callback(records) { records.forEach(function (record) { var list = record.addedNodes; var i = list.length - 1; for ( ; i > -1; i-- ) { if (list[i].nodeName === 'SELECT') { // Insert code here... console.log(list[i]); } } }); } var observer = new MutationObserver(callback); var targetNode = document.body; observer.observe(targetNode, { childList: true, subtree: true });
<script> // For testing setTimeout(function() { var $el = document.createElement('select'); document.body.appendChild($el); }, 500); </script>
Lassen Sie uns das aufschlüsseln.
var observer = new MutationObserver(callback);
Dies schafft den Betrachter. Der Beobachter beobachtet noch nichts; Hier wird der Ereignis-Listener angehängt.
observer.observe(targetNode, { childList: true, subtree: true });
Dadurch startet der Beobachter. Das erste Argument ist der Knoten, auf dem der Beobachter nach Änderungen sucht. Das zweite Argument sind die Optionen für das, worauf zu achten ist .
childList
bedeutet, dass ich darauf achten möchte, dass untergeordnete Elemente hinzugefügt oder entfernt werden.subtree
ist ein Modifikator, der erweitert wirdchildList
, um nach Änderungen an einer beliebigen Stelle im Teilbaum dieses Elements zu suchen (andernfalls werden nur Änderungen direkt darin betrachtettargetNode
).Die anderen beiden Hauptoptionen
childList
sindattributes
undcharacterData
, die bedeuten, wie sie klingen. Sie müssen eine dieser drei verwenden.function callback(records) { records.forEach(function (record) {
Im Rückruf wird es etwas knifflig. Der Rückruf empfängt ein Array von MutationRecords . Jede MutationRecord kann mehrere Änderungen eines Typs beschreiben (
childList
,attributes
odercharacterData
). Da ich dem Beobachter nur gesagt habe, er solle darauf achtenchildList
, werde ich den Typ nicht überprüfen.var list = record.addedNodes;
Genau hier greife ich zu einer NodeList aller untergeordneten Knoten, die hinzugefügt wurden. Dies ist für alle Datensätze leer, bei denen keine Knoten hinzugefügt wurden (und möglicherweise gibt es viele solcher Datensätze).
Von da an durchlaufe ich die hinzugefügten Knoten und finde alle
<select>
Elemente.Nichts wirklich komplexes hier.
jQuery
... aber du hast nach jQuery gefragt. Fein.
(function($) { var observers = []; $.event.special.domNodeInserted = { setup: function setup(data, namespaces) { var observer = new MutationObserver(checkObservers); observers.push([this, observer, []]); }, teardown: function teardown(namespaces) { var obs = getObserverData(this); obs[1].disconnect(); observers = $.grep(observers, function(item) { return item !== obs; }); }, remove: function remove(handleObj) { var obs = getObserverData(this); obs[2] = obs[2].filter(function(event) { return event[0] !== handleObj.selector && event[1] !== handleObj.handler; }); }, add: function add(handleObj) { var obs = getObserverData(this); var opts = $.extend({}, { childList: true, subtree: true }, handleObj.data); obs[1].observe(this, opts); obs[2].push([handleObj.selector, handleObj.handler]); } }; function getObserverData(element) { var $el = $(element); return $.grep(observers, function(item) { return $el.is(item[0]); })[0]; } function checkObservers(records, observer) { var obs = $.grep(observers, function(item) { return item[1] === observer; })[0]; var triggers = obs[2]; var changes = []; records.forEach(function(record) { if (record.type === 'attributes') { if (changes.indexOf(record.target) === -1) { changes.push(record.target); } return; } $(record.addedNodes).toArray().forEach(function(el) { if (changes.indexOf(el) === -1) { changes.push(el); } }) }); triggers.forEach(function checkTrigger(item) { changes.forEach(function(el) { var $el = $(el); if ($el.is(item[0])) { $el.trigger('domNodeInserted'); } }); }); } })(jQuery);
Dadurch wird
domNodeInserted
mithilfe der jQuery-API für spezielle Ereignisse ein neues Ereignis mit dem Namen erstellt . Sie können es so verwenden:$(document).on("domNodeInserted", "select", function () { $(this).combobox(); });
Ich würde persönlich vorschlagen, nach einer Klasse zu suchen, da einige Bibliotheken
select
Elemente zu Testzwecken erstellen .Natürlich können Sie die Wiedergabe auch verwenden
.off("domNodeInserted", ...)
oder optimieren, indem Sie Daten wie folgt übergeben:$(document.body).on("domNodeInserted", "select.test", { attributes: true, subtree: false }, function () { $(this).combobox(); });
Dies würde die Überprüfung des Erscheinungsbilds eines
select.test
Elements auslösen, wenn sich Attribute für Elemente direkt im Körper ändern.Sie können es live unten oder auf jsFiddle sehen .
Code-Snippet anzeigen
(function($) { $(document).on("domNodeInserted", "select", function() { console.log(this); //$(this).combobox(); }); })(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script> // For testing setTimeout(function() { var $el = document.createElement('select'); document.body.appendChild($el); }, 500); </script> <script> (function($) { var observers = []; $.event.special.domNodeInserted = { setup: function setup(data, namespaces) { var observer = new MutationObserver(checkObservers); observers.push([this, observer, []]); }, teardown: function teardown(namespaces) { var obs = getObserverData(this); obs[1].disconnect(); observers = $.grep(observers, function(item) { return item !== obs; }); }, remove: function remove(handleObj) { var obs = getObserverData(this); obs[2] = obs[2].filter(function(event) { return event[0] !== handleObj.selector && event[1] !== handleObj.handler; }); }, add: function add(handleObj) { var obs = getObserverData(this); var opts = $.extend({}, { childList: true, subtree: true }, handleObj.data); obs[1].observe(this, opts); obs[2].push([handleObj.selector, handleObj.handler]); } }; function getObserverData(element) { var $el = $(element); return $.grep(observers, function(item) { return $el.is(item[0]); })[0]; } function checkObservers(records, observer) { var obs = $.grep(observers, function(item) { return item[1] === observer; })[0]; var triggers = obs[2]; var changes = []; records.forEach(function(record) { if (record.type === 'attributes') { if (changes.indexOf(record.target) === -1) { changes.push(record.target); } return; } $(record.addedNodes).toArray().forEach(function(el) { if (changes.indexOf(el) === -1) { changes.push(el); } }) }); triggers.forEach(function checkTrigger(item) { changes.forEach(function(el) { var $el = $(el); if ($el.is(item[0])) { $el.trigger('domNodeInserted'); } }); }); } })(jQuery); </script>
Hinweis
Dieser jQuery-Code ist eine ziemlich einfache Implementierung. Es wird nicht ausgelöst, wenn Änderungen an anderer Stelle Ihren Selektor gültig machen.
Angenommen, Ihre Auswahl ist
.test select
und das Dokument hat bereits eine<select>
. Durch Hinzufügen der Klassetest
zu<body>
wird der Selektor gültig, aber da ich nurrecord.target
und überprüferecord.addedNodes
, wird das Ereignis nicht ausgelöst. Die Änderung muss an dem Element erfolgen, das Sie selbst auswählen möchten.Dies könnte vermieden werden, indem bei allen Mutationen nach dem Selektor gefragt wird. Ich habe mich dafür entschieden, dies nicht zu tun, um zu vermeiden, dass doppelte Elemente für Elemente verursacht werden, die bereits behandelt wurden. Der richtige Umgang mit benachbarten oder allgemeinen Geschwisterkombinatoren würde die Dinge noch schwieriger machen.
Für eine umfassendere Lösung finden https://github.com/pie6k/jquery.initialize , wie in erwähnt Damien Ó Ceallaigh ‚s Antwort . Der Autor dieser Bibliothek hat jedoch angekündigt, dass die Bibliothek alt ist, und schlägt vor, dass Sie dafür jQuery nicht verwenden sollten.
quelle
Ich habe gerade diese Lösung gefunden, die alle meine Ajax-Probleme zu lösen scheint.
Für On-Ready-Events verwende ich jetzt Folgendes:
function loaded(selector, callback){ //trigger after page load. $(function () { callback($(selector)); }); //trigger after page update eg ajax event or jquery insert. $(document).on('DOMNodeInserted', selector, function () { callback($(this)); }); } loaded('.foo', function(el){ //some action el.css('background', 'black'); });
Und für normale Triggerereignisse verwende ich jetzt Folgendes:
$(document).on('click', '.foo', function () { //some action $(this).css('background', 'pink'); });
quelle
Es gibt ein Plugin, adampietrasiak / jquery.initialize , das darauf basiert
MutationObserver
, dies einfach zu erreichen.$.initialize(".some-element", function() { $(this).css("color", "blue"); });
quelle
Dies ist möglich,
DOM4 MutationObservers
funktioniert aber ( vorerst) nur in Firefox 14 + / Chrome 18+.Es gibt jedoch einen " epischen Hack " (die Worte des Autors gehören nicht mir!), Der in allen Browsern funktioniert, die CSS3-Animationen unterstützen: IE10, Firefox 5+, Chrome 3+, Opera 12, Android 2.0+, Safari 4+. Siehe die Demo aus dem Blog. Der Hack besteht darin, ein CSS3-Animationsereignis mit einem bestimmten Namen zu verwenden, das in JavaScript beobachtet und verarbeitet wird.
quelle
Eine Möglichkeit, die scheint zuverlässig (wenn auch nur getestet in Firefox und Chrome) ist JavaScript zu verwenden , um das zu hören
animationend
(oder seine camelcase, und das Präfix, GeschwisteranimationEnd
) Ereignis und wendet eine kurzlebige (in der Demo 0,01 Sekunden) Animation Der Elementtyp, den Sie hinzufügen möchten. Dies ist natürlich keinonCreate
Ereignis, sondern entspricht (in kompatiblen Browsern) eineronInsertion
Art von Ereignis. Das Folgende ist ein Proof-of-Concept:$(document).on('webkitAnimationEnd animationend MSAnimationEnd oanimationend', function(e){ var eTarget = e.target; console.log(eTarget.tagName.toLowerCase() + ' added to ' + eTarget.parentNode.tagName.toLowerCase()); $(eTarget).draggable(); // or whatever other method you'd prefer });
Mit folgendem HTML:
<div class="wrapper"> <button class="add">add a div element</button> </div>
Und (abgekürzt, Präfixversionen entfernt, obwohl in der Geige unten vorhanden) CSS:
/* vendor-prefixed alternatives removed for brevity */ @keyframes added { 0% { color: #fff; } } div { color: #000; /* vendor-prefixed properties removed for brevity */ animation: added 0.01s linear; animation-iteration-count: 1; }
JS Fiddle Demo .
Offensichtlich kann das CSS an die Platzierung der relevanten Elemente sowie an den in der jQuery verwendeten Selektor angepasst werden (es sollte wirklich so nah wie möglich am Einfügepunkt sein).
Dokumentation der Ereignisnamen:
Verweise:
animationend
Herstellerunterstützung .quelle
Für mich funktioniert die Bindung an den Körper nicht. Das Binden an das Dokument mit jQuery.bind () funktioniert.
$(document).bind('DOMNodeInserted',function(e){ var target = e.target; });
quelle
Ich denke, es ist erwähnenswert, dass dies in einigen Fällen funktionieren würde:
$( document ).ajaxComplete(function() { // Do Stuff });
quelle
Erstellen Sie eine
<select>
mit ID, hängen Sie sie an das Dokument an .. und rufen Sie an.combobox
var dynamicScript='<select id="selectid"><option value="1">...</option>.....</select>' $('body').append(dynamicScript); //append this to the place your wanted. $('#selectid').combobox(); //get the id and add .combobox();
Dies sollte den Trick machen. Sie können die Auswahl ausblenden, wenn Sie möchten und nach dem
.combobox
Anzeigen. Oder verwenden Sie find.$(document).find('select').combobox() //though this is not good performancewise
quelle
anstatt...
$(".class").click( function() { // do something });
Du kannst schreiben...
$('body').on('click', '.class', function() { // do something });
quelle
Wenn Sie anglejs verwenden, können Sie Ihre eigene Direktive schreiben. Ich hatte das gleiche Problem mit bootstrapSwitch. Ich muss
$("[name='my-checkbox']").bootstrapSwitch();
Javascript aufrufen, aber mein HTML-Eingabeobjekt wurde zu diesem Zeitpunkt nicht erstellt. Also schreibe ich eine eigene Direktive und erstelle das Eingabeelement mit<input type="checkbox" checkbox-switch>
In der Direktive kompiliere ich das Element, um über Javascript Zugriff zu erhalten und den Befehl jquery auszuführen (wie Ihren
.combobox()
Befehl). Sehr wichtig ist es, das Attribut zu entfernen. Andernfalls ruft sich diese Direktive selbst auf und Sie haben eine Schleife erstelltapp.directive("checkboxSwitch", function($compile) { return { link: function($scope, element) { var input = element[0]; input.removeAttribute("checkbox-switch"); var inputCompiled = $compile(input)($scope.$parent); inputCompiled.bootstrapSwitch(); } } });
quelle