Esecuzione di Javascript quando viene aggiunto un widget nel back-end


20

Ho dei widget a cui sono collegati controlli javascript.

Se il widget è presente quando viene caricata la pagina di amministrazione del widget, i controlli funzionano correttamente.

Quando aggiungo un nuovo widget, non funzionano correttamente, ottengo il markup, ma non hanno effetto eventi javascript.

Se salvo il nuovo widget, quando il modulo viene ricaricato, i controlli vengono creati correttamente e ora funzionano.

L'aggiornamento della pagina risolve anche il problema, ma solo per i widget esistenti. I nuovi widget hanno ancora questo problema.

In particolare sto eseguendo selectize su input selezionati in questi punti:

  • documento pronto
  • Ajaxcomplete

Ho verificato che il mio codice sia eseguito su ogni evento come desiderato, ma i risultati non sono quelli previsti.

Ecco un plug-in di prova che dimostra il problema:

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

Vedrai che ho un contatore che aumenta con ogni elemento selezionato che riesce a convertire.

Gli appunti:

  • Quando viene caricata la pagina del widget, posso vedere il contatore aumentare nella console JS come previsto
  • Quando aggiungo un nuovo widget, il codice viene eseguito, tuttavia, non riesce a trovare tutti gli elementi selezionati su cui può essere eseguito, come dimostrato da found.length essendo 0. Questo non dovrebbe essere il caso, come ogni nuovo widget di quel tipo dovrebbe avere un elemento select
  • elementi selezionati hanno una classe per identificarli, questa classe viene rimossa una volta applicata la libreria selectize per impedire la duplicazione e la rielaborazione su widget esistenti.
  • Prima di usare selectize, ho usato Select2, che aveva lo stesso problema
  • Commentando il codice AJAX, mi aspetto che i nuovi widget abbiano un input di selezione standard. Loro non. Non so perché sia ​​così

Quindi, come faccio a far funzionare il controllo selectize senza dire all'utente di aggiornare / fare clic su Salva prima di apportare modifiche?


È un problema di delega di eventi. Dovrai esaminare il .on()metodo jQuerys . Il che richiede di associare un evento al documento. Tuttavia, quale evento sarà appropriato non sono sicuro in questo momento. In definitiva è perché i tuoi collegamenti originali rappresentano la versione iniziale del DOM quando la pagina è stata caricata e per la maggior parte sono ciechi rispetto ai nuovi elementi (contenuto del widget) che vengono aggiunti tramite Ajax. Spero che ti indichi nella giusta direzione, se non posso rispondere meglio quando sono al lavoro.

Questo è quello che mi aspettavo e perché ho aggiunto la jQuery( document ).ajaxStop( function() {parte in modo da poter inizializzare i controlli nei widget appena caricati. Tuttavia, se avessi rimosso quella riga, mi sarei aspettato che i nuovi widget avessero input di selezione HTML standard, ma non = s
Tom J Nowell

Come ha commentato @ aaron-holbrook, il suo approccio è il più pulito usando gli eventi widget-updatede widget-added. Inoltre, voglio sottolineare, nel codice @michaeljames, l'uso dell'elemento id #widgets-right. Assicurati di usarlo per scegliere come target elementi widget attivi all'interno del tuo codice JS altrimenti potresti ottenere elementi duplicati poiché il tuo codice potrebbe anche selezionare elementi widget inattivi nascosti sul lato sinistro dello schermo (e questi verranno clonati quando il widget viene aggiunto).
Julien,

Risposte:


12

Grandi notizie,

L'ho risolto.

Mi scuso per aver perso l'essenza nel mio commento iniziale e per averti dato una risposta che avevi già implementato. Questo mi insegnerà a rispondere sul mio telefono mentre sono in treno!

L'uso di ajaxstop è corretto. Diavolo JS per la maggior parte funziona correttamente, potresti vedere gli stili CSS inizializzati e le modifiche nel DOM.

Il problema sta in effetti con il tuo selettore.

Questo perché il contenuto del widget non viene caricato tramite ajax, in realtà lo clona dalla colonna di sinistra in cui è nascosto e quindi genera una chiamata ajax per salvare la posizione del widget nella colonna di destra. Questo spiega perché ajaxstop funziona a meraviglia, anche se il contenuto viene clonato. Tuttavia, poiché esiste una versione nascosta del widget nella colonna di sinistra, il tuo JS sta creando un'istanza. Pertanto, trascinandolo nella colonna di destra, si ottiene un clone alterato del widget nascosto.

Quindi è necessario selezionare quello nella parte sinistra. Di seguito è riportato il codice corretto:

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

Santo cielo, devo andare a provare questo <3
Tom J Nowell

Soluzione molto elegante per un forte mal di testa!
bosco,

3
Vorrei sconsigliarti di correre su ogni singolo evento "ajaxStop" e suggerirei invece di utilizzare gli eventi "aggiunti con widget" e "aggiornati con widget".
Tyrun,

16

Come ha commentato @ aaron-holbrook, un approccio più pulito sarà quello di fare:

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

In molti casi vorrai anche eseguire JS quando la pagina viene caricata e quando i widget vengono aggiornati. Puoi farlo in questo modo.

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

Basta incollare qui come riferimento in quanto le risposte sono molto più facili da trovare per i commenti


2
probabilmente dovrebbe usare jQuery invece di $
Mark Kaplun l'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.