Exécution de Javascript lorsqu'un widget est ajouté dans le backend

20

J'ai des widgets auxquels des contrôles javascript sont attachés.

Si le widget est présent lors du chargement de la page d'administration du widget, les contrôles fonctionnent correctement.

Lorsque j'ajoute un nouveau widget, ils ne fonctionnent pas correctement, j'obtiens le balisage, mais aucun événement javascript ne prend effet.

Si j'enregistre le nouveau widget, lorsque le formulaire se recharge, les contrôles sont créés correctement et fonctionnent maintenant.

L'actualisation de la page résout également le problème, mais uniquement pour les widgets existants. Les nouveaux widgets ont toujours ce problème.

Plus précisément, je lance selectize sur certaines entrées à ces points:

  • document prêt
  • Ajaxcomplete

J'ai vérifié que mon code est exécuté sur chaque événement comme souhaité, mais les résultats ne sont pas ceux attendus.

Voici un plugin de test qui illustre le problème:

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

Vous verrez que j'ai un compteur qui augmente avec chaque élément sélectionné qu'il trouve qu'il peut convertir.

Remarques:

  • Lorsque la page du widget se charge, je peux voir le compteur augmenter dans la console JS comme prévu
  • Lorsque j'ajoute un nouveau widget, le code est exécuté, cependant, il ne trouve aucun élément de sélection sur lequel il peut s'exécuter, comme démontré par found.length étant 0. Cela ne devrait pas être le cas, comme chaque nouveau widget de ce type devrait avoir un élément select
  • les éléments select ont une classe pour les identifier, cette classe est supprimée une fois la bibliothèque selectize appliquée pour éviter la duplication et le retraitement sur les widgets existants.
  • Avant d'utiliser selectize, j'ai utilisé Select2, qui avait le même problème
  • Commentant le code AJAX, je m'attendrais à ce que les nouveaux widgets aient une entrée de sélection standard. Ils ne. Je ne sais pas pourquoi c'est le cas

Alors, comment puis-je faire fonctionner le contrôle de sélection sans dire à l'utilisateur d'actualiser / cliquer sur Enregistrer avant d'apporter des modifications?

Tom J Nowell
la source
C'est un problème de délégation d'événement. Vous devrez examiner l'utilisation de la .on()méthode jQuerys . Ce qui vous oblige à lier un événement au document. Cependant, quel événement sera approprié, je ne suis pas sûr pour le moment. En fin de compte, c'est parce que vos liaisons d'origine représentent la version initiale du DOM lorsque la page a été chargée et sont pour la plupart aveugles aux nouveaux éléments (contenu du widget) qui sont ajoutés via ajax. J'espère que cela vous indiquera la bonne direction, sinon je pourrai mieux répondre lorsque je serai au travail.
C'est ce que j'attendais, et pourquoi j'ai ajouté la jQuery( document ).ajaxStop( function() {partie afin de pouvoir initialiser les contrôles dans les widgets nouvellement chargés. Cependant, si je supprimais cette ligne, je m'attendrais à ce que les nouveaux widgets aient des entrées de sélection HTML standard, mais ils ne le sont pas
Tom J Nowell
Comme l'a fait remarquer @ aaron-holbrook, son approche est la plus propre en utilisant les événements widget-updatedet widget-added. Je tiens également à souligner, dans le code @michaeljames, l'utilisation de l'ID d'élément #widgets-right. Assurez-vous de l'utiliser pour cibler les éléments de widgets actifs dans votre code JS, sinon vous pourriez obtenir des éléments en double car votre code peut également sélectionner des éléments de widget inactifs cachés sur le côté gauche de l'écran (et ceux qui sont clonés lorsque le widget est ajouté).
Julien

Réponses:

12

Bonne nouvelle,

Je l'ai corrigé.

Toutes mes excuses pour avoir manqué votre sens dans mon commentaire initial et pour vous avoir donné une réponse que vous aviez déjà mise en œuvre. Cela m'apprendra à répondre sur mon téléphone en train!

Votre utilisation d'ajaxstop est correcte. Enfer le JS pour la plupart fonctionne correctement, vous pouvez voir les styles css en cours d'initialisation et les changements dans le DOM.

Le problème réside en fait avec votre sélecteur.

Cela est dû au fait que le contenu du widget n'est pas chargé via ajax, en fait, il le clone à partir de la colonne de gauche où il est caché, puis déclenche un appel ajax pour enregistrer la position du widget dans la colonne de droite. Cela explique pourquoi ajaxstop fonctionne comme un régal, même le contenu de la pensée est cloné. Cependant, comme il y a une version cachée du widget dans la colonne de gauche, votre JS instancie cela. Ainsi, lorsque vous le faites glisser vers la colonne de droite, vous obtenez un clone déformé du widget caché.

Vous devez donc sélectionner celui sur le côté gauche. Voici le code corrigé:

<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>
kaiser
la source
Holy moly, je dois aller tester ça <3
Tom J Nowell
Solution très élégante à un mal de tête majeur!
bosco
3
Je déconseille de courir sur chaque événement 'ajaxStop' et je suggère plutôt d'utiliser les événements 'widget-added' ainsi que 'widget-updated'.
Tyrun
16

Comme l'a fait remarquer @ aaron-holbrook, une approche plus propre consistera à:

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

Dans de nombreux cas, vous souhaiterez également exécuter le JS lors du chargement de la page ainsi que lorsque les widgets sont mis à jour. Vous pouvez le faire comme ça.

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

Il suffit de coller ici pour référence car les réponses sont beaucoup plus faciles à trouver que les commentaires

chifliiiii
la source
2
devrait probablement utiliser jQuery au lieu de $
Mark Kaplun