Ejecutar Javascript cuando se agrega un widget en el backend

20

Tengo widgets que tienen controles javascript adjuntos.

Si el widget está presente cuando se carga la página de administración del widget, los controles funcionan correctamente.

Cuando agrego un nuevo widget, no funcionan correctamente, obtengo el marcado, pero no surten efecto los eventos de JavaScript.

Si guardo el nuevo widget, cuando el formulario se vuelve a cargar, los controles se crean correctamente y ahora funcionan.

Actualizar la página también soluciona el problema, pero solo para los widgets existentes. Los nuevos widgets aún tienen este problema.

Específicamente, estoy ejecutando selectize en las entradas seleccionadas en estos puntos:

  • documento listo
  • Ajaxcomplete

Verifiqué que mi código se ejecuta en cada evento según lo deseado, pero los resultados no son los esperados.

Aquí hay un complemento de prueba que demuestra el problema:

https://gist.github.com/Tarendai/8466299

Verá que tengo un contador que aumenta con cada elemento seleccionado que encuentra que puede convertir.

Notas:

  • Cuando se carga la página del widget, puedo ver que el contador aumenta en la consola JS como se esperaba
  • Cuando agrego un nuevo widget, el código se ejecuta, sin embargo, no puede encontrar ningún elemento seleccionado en el que pueda ejecutarse, como lo demuestra found.length siendo 0. Este no debería ser el caso, ya que cada nuevo widget de ese tipo debería tener un elemento seleccionado
  • los elementos select tienen una clase para identificarlos, esta clase se elimina una vez que se aplica la biblioteca selectize para evitar la duplicación y el reprocesamiento en los widgets existentes.
  • Antes de usar selectize, usé Select2, que tenía el mismo problema
  • Al comentar el código AJAX, esperaría que los nuevos widgets tengan una entrada de selección estándar. Ellos no. No se porque este es el caso

Entonces, ¿cómo hago para que el control selectize funcione sin decirle al usuario que actualice / haga clic en guardar antes de realizar cambios?

Tom J Nowell
fuente
Es un problema de delegación de eventos. Deberá analizar el uso del .on()método jQuerys . Lo que requiere que vincule un evento al documento. Sin embargo, qué evento será apropiado, no estoy seguro en este momento. En última instancia, es porque sus enlaces originales representan la versión inicial del DOM cuando se cargó la página y en su mayor parte son ciegos a los nuevos elementos (contenido del widget) que se agregan a través de ajax. Espero que eso te señale en la dirección correcta, si no puedo responder mejor cuando estoy en el trabajo.
Esto es lo que esperaba y por qué agregué la jQuery( document ).ajaxStop( function() {parte para poder inicializar los controles en los widgets recién cargados. Sin embargo, si elimino esa línea, esperaría que los nuevos widgets tengan entradas de selección HTML estándar, pero no = s
Tom J Nowell
Como comentó @ aaron-holbrook, su enfoque es el más limpio al usar los eventos widget-updatedy widget-added. También quiero enfatizar, en el código @michaeljames, el uso del elemento id #widgets-right. Asegúrese de usarlo para apuntar a elementos de widgets activos dentro de su código JS; de lo contrario, podría obtener elementos duplicados ya que su código también puede seleccionar elementos de widget inactivos ocultos en el lado izquierdo de la pantalla (y esos se clonan cuando se agrega el widget).
Julien

Respuestas:

12

Una gran noticia,

Lo he arreglado

Disculpas por perder tu esencia en mi comentario inicial y darte una respuesta que ya habías implementado. ¡Eso me enseñará a responder en mi teléfono mientras estoy en un tren!

Su uso de ajaxstop es correcto. Demonios, el JS en su mayor parte funciona correctamente, podría ver los estilos CSS que se inicializan y los cambios en el DOM.

El problema radica en su selector.

Esto se debe a que el contenido del widget no se carga a través de ajax, de hecho, lo clona desde la columna de la izquierda donde está oculto y luego dispara una llamada de ajax para guardar la posición del widget en la columna de la derecha. Esto explica por qué ajaxstop funciona de maravilla, incluso si el contenido está clonado. Sin embargo, debido a que hay una versión oculta del widget en la columna de la izquierda, su JS está instanciando sobre eso. Como tal, cuando lo arrastra a la columna de la derecha, obtiene un clon destrozado del widget oculto.

Por lo tanto, debe seleccionar el que está en el lado izquierdo. A continuación se muestra el código corregido:

<script>
jQuery( document ).ready( function( $ ) {
    function runSelect() {
        var found = $( '#widgets-right select.testselectize' );
        found.each( function( index, value ) {

            $( value ).selectize();
                .removeClass( 'testselectize' )
                .addClass( 'run-' + window.counter );

            console.log( $val );
            window.counter++;
        } );
    }

    window.counter = 1;

    runSelect();

    $( document ).ajaxStop( function() {
        runSelect();
    } );
} );
</script>
emperador
fuente
Santo cielo, tengo que ir a probar esto <3
Tom J Nowell
¡Una solución muy elegante para un gran dolor de cabeza!
bosco
3
Aconsejaría que no se ejecute en todos los eventos 'ajaxStop' y, en su lugar, sugiera usar en eventos 'widgets agregados' y 'widgets actualizados'.
Tyrun
16

Como comentó @ aaron-holbrook, un enfoque más limpio será hacer:

jQuery(document).on('widget-updated widget-added', function(){
    // your code to run
});

En muchos casos, también querrá ejecutar JS cuando se cargue la página y cuando se actualicen los widgets. Puedes hacerlo así.

function handle_widget_loading(){
   // your code to run
}
jQuery(document).ready( handle_widget_loading );
jQuery(document).on('widget-updated widget-added', handle_widget_loading );

Simplemente pegando aquí como referencia, las respuestas son mucho más fáciles de encontrar.

chifliiiii
fuente
2
probablemente debería usar jQuery en lugar de $
Mark Kaplun