Ausführen von Javascript, wenn ein Widget im Backend hinzugefügt wird


20

Ich habe Widgets, an die Javascript-Steuerelemente angehängt sind.

Wenn das Widget beim Laden der Widget-Verwaltungsseite vorhanden ist, funktionieren die Steuerelemente ordnungsgemäß.

Wenn ich ein neues Widget hinzufüge, funktionieren diese nicht ordnungsgemäß. Ich erhalte das Markup, aber es werden keine JavaScript-Ereignisse wirksam.

Wenn ich das neue Widget speichere, werden die Steuerelemente beim erneuten Laden des Formulars korrekt erstellt und funktionieren jetzt.

Das Aktualisieren der Seite behebt ebenfalls das Problem, jedoch nur für vorhandene Widgets. Neue Widgets haben dieses Problem immer noch.

Insbesondere lasse ich an folgenden Punkten selectize auf ausgewählten Eingängen ausführen:

  • Dokument bereit
  • Ajaxcomplete

Ich habe überprüft, ob mein Code bei jedem Ereignis wie gewünscht ausgeführt wird, aber die Ergebnisse sind nicht wie erwartet.

Hier ist ein Test-Plugin, das das Problem demonstriert:

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

Sie werden sehen, dass ich einen Zähler habe, der sich mit jedem ausgewählten Element erhöht, das konvertiert werden kann.

Anmerkungen:

  • Wenn die Widget-Seite geladen wird, wird der Zähler in der JS-Konsole wie erwartet erhöht
  • Wenn ich ein neues Widget hinzufüge, wird der Code ausgeführt, es werden jedoch keine ausgewählten Elemente gefunden, auf denen er ausgeführt werden kann. Dies wird dadurch demonstriert, dass found.length 0 ist. Dies sollte nicht der Fall sein, wie dies bei jedem neuen Widget dieses Typs der Fall sein sollte habe ein ausgewähltes Element
  • ausgewählte Elemente haben eine Klasse, um sie zu identifizieren. Diese Klasse wird entfernt, sobald die Auswahlbibliothek angewendet wird, um ein Duplizieren und erneutes Verarbeiten auf vorhandenen Widgets zu verhindern.
  • Vor der Verwendung von selectize habe ich Select2 verwendet, bei dem das gleiche Problem auftrat
  • Wenn ich den AJAX-Code auskommentiere, würde ich erwarten, dass neue Widgets eine Standardauswahleingabe haben. Sie nicht. Ich weiß nicht, warum das so ist

Wie kann ich das Steuerelement selectize aktivieren, ohne den Benutzer aufzufordern, vor dem Vornehmen von Änderungen zu aktualisieren / auf Speichern zu klicken?


Es ist ein Problem der Event-Delegation. Sie müssen sich mit der jQuerys- .on()Methode auseinandersetzen. Dazu müssen Sie ein Ereignis an das Dokument binden. Welches Ereignis jedoch angemessen sein wird, weiß ich derzeit nicht genau. Letztendlich liegt es daran, dass Ihre ursprünglichen Bindungen die ursprüngliche Version des DOM darstellen, als die Seite geladen wurde, und für die neuen Elemente (Widget-Inhalt), die über Ajax hinzugefügt werden, größtenteils blind sind. Hoffentlich weist das Sie in die richtige Richtung, wenn nicht, kann ich besser antworten, wenn ich bei der Arbeit bin.

Dies ist, was ich erwartet und warum ich das jQuery( document ).ajaxStop( function() {Teil hinzugefügt habe, damit ich die Steuerelemente in den neu geladenen Widgets initialisieren kann. Wenn ich diese Zeile jedoch entfernen würde, würde ich erwarten, dass neue Widgets Standardeingaben für die HTML-Auswahl haben, aber dies ist nicht der Fall
Tom J Nowell

Wie @ aaron-holbrook kommentierte, ist sein Ansatz der sauberste unter Verwendung der Ereignisse widget-updatedund widget-added. Außerdem möchte ich in @michaeljames Code die Verwendung der Element-ID hervorheben #widgets-right. Verwenden Sie diese Option unbedingt , um aktive Widgets-Elemente in Ihrem JS-Code als Ziel festzulegen. Andernfalls erhalten Sie möglicherweise doppelte Elemente, da in Ihrem Code möglicherweise auch ausgeblendete inaktive Widget-Elemente auf der linken Seite des Bildschirms ausgewählt werden (und diese werden geklont, wenn das Widget hinzugefügt wird).
Julien

Antworten:


12

Großartige Neuigkeiten,

Ich habe es behoben.

Entschuldigen Sie, dass Sie in meinem ersten Kommentar nicht auf Ihre Idee eingegangen sind und Ihnen eine Antwort gegeben haben, die Sie bereits umgesetzt haben. Das bringt mir bei, in einem Zug auf meinem Handy zu antworten!

Ihre Verwendung von Ajaxstop ist korrekt. Zur Hölle, der JS funktioniert größtenteils einwandfrei. Sie konnten sehen, wie die CSS-Stile initialisiert wurden und welche Änderungen im DOM vorgenommen wurden.

Das Problem liegt in der Tat bei Ihrer Auswahl.

Dies liegt daran, dass der Widget-Inhalt nicht über Ajax geladen wird. Tatsächlich wird er aus der linken Spalte geklont, wo er ausgeblendet ist, und anschließend wird ein Ajax-Aufruf ausgelöst, um die Position des Widgets in der rechten Spalte zu speichern. Dies erklärt, warum Ajaxstop eine Wohltat ist, auch wenn Gedankeninhalte geklont werden. Da sich jedoch in der linken Spalte eine versteckte Version des Widgets befindet, wird dies von Ihrem JS instanziiert. Wenn Sie es in die rechte Spalte ziehen, erhalten Sie einen entstellten Klon des versteckten Widgets.

Daher müssen Sie die auf der linken Seite auswählen. Unten ist der korrigierte Code:

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

Holy Moly, ich muss diesen Test machen <3
Tom J Nowell

Sehr elegante Lösung für starke Kopfschmerzen!
Bosco

3
Ich rate davon ab, bei jedem einzelnen "AjaxStop" -Ereignis ausgeführt zu werden, und empfehle stattdessen die Verwendung von "Widget-hinzugefügten" und "Widget-aktualisierten" Ereignissen.
Tyrun

16

Wie @ aaron-holbrook kommentierte, wird ein sauberer Ansatz zu tun sein:

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

In vielen Fällen möchten Sie den JS auch ausführen, wenn die Seite geladen wird und wenn die Widgets aktualisiert werden. Sie können dies so tun.

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

Das Einfügen hier als Referenz, da Antworten viel einfacher sind, diese Kommentare zu finden


2
sollte wahrscheinlich jQuery anstelle von $ verwenden
Mark Kaplun
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.