Necesito poder crear <select>
elementos dinámicamente y convertirlos en jQuery .combobox()
. Este debería ser un evento de creación de elementos, a diferencia de algún evento de "clic", en cuyo caso podría usar jQuery .on()
.
Entonces, ¿existe algo como esto?
$(document).on("create", "select", function() {
$(this).combobox();
}
Soy reacio a usar livequery porque está muy desactualizado.
ACTUALIZAR La selección / combobox mencionada se carga a través de ajax en un jQuery colorbox (ventana modal), por lo tanto, el problema: solo puedo iniciar el combobox usando el colorbox onComplete
, sin embargo, al cambiar un combobox, otro select / combobox debe crearse dinámicamente, por lo tanto, necesito un forma más genérica de detectar la creación de un elemento ( select
en este caso).
ACTUALIZACIÓN2 Para tratar de explicar el problema más a fondo, tengo select/combobox
elementos creados de forma recursiva, también hay mucho código de inicio en el interior .combobox()
, por lo tanto, si usara un enfoque clásico, como en la respuesta de @ bipen , mi código se inflaría a niveles insanos. Espero que esto explique mejor el problema.
ACTUALIZACIÓN3 Gracias a todos, ahora entiendo que desde la desaprobación de DOMNodeInserted
, queda un vacío en la mutación DOM y no hay solución para este problema. Solo tendré que repensar mi aplicación.
fuente
$(select).ready(function() { });
ready
se usa para: "Especificar una función para ejecutar cuando el DOM esté completamente cargado". (de jquery.com)combobox()
método en el punto de creación / inserción, en lugar de hacerlo después?$(document).on('onComplete', 'select', function(){ // bind here? });
? (Sindocument
embargo, obviamente use un padre más cercano que el )Respuestas:
Puede que
on
elDOMNodeInserted
evento obtenga un evento para cuando se agregue al documento mediante su código.$('body').on('DOMNodeInserted', 'select', function () { //$(this).combobox(); }); $('<select>').appendTo('body'); $('<select>').appendTo('body');
Jugado aquí: http://jsfiddle.net/Codesleuth/qLAB2/3/
EDITAR: después de leer, solo necesito verificar dos veces
DOMNodeInserted
que no causará problemas en los navegadores. Esta pregunta de 2010 sugiere que IE no es compatible con el evento, así que pruébelo si puede.Vea aquí: [enlace] ¡Advertencia! el tipo de evento DOMNodeInserted se define en esta especificación para referencia y completitud, pero esta especificación desaprueba el uso de este tipo de evento.
fuente
.delegate
obsoleto de la versión 1.7 de jQuery y reemplazado por.on
?DOMNodeInserted
que ahora está en desuso.on('DOMNodeInserted'
antes de publicar esta pregunta. Obviamente no funcionó.Puede usar elDOMNodeInserted
evento de mutación (no necesita delegación):$('body').on('DOMNodeInserted', function(e) { var target = e.target; //inserted element; });
EDITAR: Los eventos de mutación están en desuso , use el observador de mutación en su lugar
fuente
Como se mencionó en varias otras respuestas, los eventos de mutación se han desaprobado, por lo que debería usar MutationObserver en su lugar. Como nadie ha dado detalles al respecto todavía, aquí va ...
API de JavaScript básica
La API de MutationObserver es bastante simple. No es tan simple como los eventos de mutación, pero aún está bien.
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>
Analicemos eso.
var observer = new MutationObserver(callback);
Esto crea al observador. El observador aún no está mirando nada; aquí es donde se adjunta el detector de eventos.
observer.observe(targetNode, { childList: true, subtree: true });
Esto hace que el observador se ponga en marcha. El primer argumento es el nodo en el que el observador observará los cambios. El segundo argumento son las opciones de qué estar atento .
childList
significa que quiero ver si se agregan o eliminan elementos secundarios.subtree
es un modificador que se extiendechildList
para observar cambios en cualquier parte del subárbol de este elemento (de lo contrario, solo miraría los cambios directamente dentrotargetNode
).Las otras dos opciones principales además
childList
sonattributes
ycharacterData
, lo que significa cómo suenan. Debes usar uno de esos tres.function callback(records) { records.forEach(function (record) {
Las cosas se ponen un poco complicadas dentro de la devolución de llamada. La devolución de llamada recibe una matriz de MutationRecord s. Cada MutationRecord puede describir varios cambios de un tipo (
childList
,attributes
ocharacterData
). Como solo le dije al observador que estuviera atentochildList
, no me molestaré en verificar el tipo.var list = record.addedNodes;
Aquí mismo tomo una NodeList de todos los nodos secundarios que se agregaron. Esto estará vacío para todos los registros donde no se agregan nodos (y puede haber muchos registros de este tipo).
A partir de ahí, recorro los nodos agregados y encuentro los que son
<select>
elementos.Nada realmente complejo aquí.
jQuery
... pero pediste jQuery. Multa.
(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);
Esto crea un nuevo evento llamado
domNodeInserted
, usando la API de eventos especiales de jQuery . Puedes usarlo así:$(document).on("domNodeInserted", "select", function () { $(this).combobox(); });
Personalmente, sugeriría buscar una clase porque algunas bibliotecas crearán
select
elementos con fines de prueba.Naturalmente, también puede utilizar
.off("domNodeInserted", ...)
o ajustar la visualización pasando datos como este:$(document.body).on("domNodeInserted", "select.test", { attributes: true, subtree: false }, function () { $(this).combobox(); });
Esto activaría la comprobación de la apariencia de un
select.test
elemento cada vez que cambiaran los atributos de los elementos directamente dentro del cuerpo.Puede verlo en vivo a continuación o en jsFiddle .
Mostrar fragmento de código
(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>
Nota
Este código jQuery es una implementación bastante básica. No se activa en los casos en que las modificaciones en otros lugares hacen que su selector sea válido.
Por ejemplo, suponga que su selector es
.test select
y el documento ya tiene una extensión<select>
. Agregar la clasetest
a<body>
hará que el selector sea válido, pero debido a que solo verificorecord.target
yrecord.addedNodes
, el evento no se activará. El cambio tiene que ocurrir en el elemento que desea seleccionar.Esto podría evitarse consultando el selector siempre que ocurran mutaciones. Elegí no hacer eso para evitar causar eventos duplicados para elementos que ya habían sido manejados. Tratar adecuadamente con combinadores hermanos adyacentes o generales complicaría aún más las cosas.
Para obtener una solución más completa, consulte https://github.com/pie6k/jquery.initialize , como se menciona en la respuesta de Damien Ó Ceallaigh . Sin embargo, el autor de esa biblioteca ha anunciado que la biblioteca es antigua y sugiere que no debería usar jQuery para esto.
fuente
Se me ocurrió esta solución que parece resolver todos mis problemas de ajax.
Para eventos listos, ahora uso esto:
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'); });
Y para eventos desencadenantes normales ahora uso esto:
$(document).on('click', '.foo', function () { //some action $(this).css('background', 'pink'); });
fuente
Hay un complemento, adampietrasiak / jquery.initialize , que se basa en
MutationObserver
que lo logra de manera simple.$.initialize(".some-element", function() { $(this).css("color", "blue"); });
fuente
Esto se podría hacer con,
DOM4 MutationObservers
pero solo funcionará en Firefox 14 + / Chrome 18+ (por ahora).Sin embargo, hay un " truco épico " (¡las palabras del autor no son mías!) Que funciona en todos los navegadores que admiten animaciones CSS3 que son: IE10, Firefox 5+, Chrome 3+, Opera 12, Android 2.0+, Safari 4+. Vea la demostración del blog. El truco consiste en utilizar un evento de animación CSS3 con un nombre dado que se observa y se actúa en JavaScript.
fuente
Una forma, que parece confiable (aunque probada solo en Firefox y Chrome) es usar JavaScript para escuchar el
animationend
evento (o su camelCased, y prefijo, hermanoanimationEnd
), y aplicar una animación de corta duración (en la demostración de 0.01 segundos) a el tipo de elemento que planea agregar. Esto, por supuesto, no es unonCreate
evento, pero se aproxima (en navegadores compatibles ) a unonInsertion
tipo de evento; la siguiente es una prueba de concepto:$(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 });
Con el siguiente HTML:
<div class="wrapper"> <button class="add">add a div element</button> </div>
Y (abreviado, prefijo-versiones-eliminado aunque presente en Fiddle, a continuación) 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; }
Demostración de JS Fiddle .
Obviamente, el CSS se puede ajustar para adaptarse a la ubicación de los elementos relevantes, así como al selector utilizado en jQuery (realmente debería estar lo más cerca posible del punto de inserción).
Documentación de los nombres de los eventos:
Referencias:
animationend
Soporte de proveedor de JavaScript .fuente
Para mí, atarme al cuerpo no funciona. La vinculación al documento mediante jQuery.bind () sí lo hace.
$(document).bind('DOMNodeInserted',function(e){ var target = e.target; });
fuente
Creo que vale la pena mencionar que, en algunos casos, esto funcionaría:
$( document ).ajaxComplete(function() { // Do Stuff });
fuente
en vez de...
$(".class").click( function() { // do something });
Puedes escribir...
$('body').on('click', '.class', function() { // do something });
fuente
crea un
<select>
con id, añádelo al documento .. y llama.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();
esto debería hacer el truco ... puedes ocultar la selección si quieres y luego
.combobox
mostrarla ... o usar buscar ...$(document).find('select').combobox() //though this is not good performancewise
fuente
si está utilizando angularjs, puede escribir su propia directiva. Tuve el mismo problema con bootstrapSwitch. Tengo que llamar
$("[name='my-checkbox']").bootstrapSwitch();
a javascript pero mi objeto de entrada html no se creó en ese momento. Entonces escribo una directiva propia y creo el elemento de entrada con<input type="checkbox" checkbox-switch>
En la directiva, compilo el elemento para obtener acceso a través de javascript y ejecutar el comando jquery (como su
.combobox()
comando). Muy importante es eliminar el atributo. De lo contrario, esta directiva se llamará a sí misma y habrá creado un bucleapp.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(); } } });
fuente