36 votes

La Force de re-cuisson de tous (scripts / fonctions) sur ajaxed contenu

tl;dr

J'utilise ajax pour récupérer de nouveaux contenus. Le contenu est récupéré et ajouté à la page. Cependant, les scripts ne sont pas "re-le-feu" à cause de leurs appels à l'extérieur de la ajaxed div.

Les scripts de chargement et de feu sans aucun problème sur chargement initial de la page, mais pas quand je l'ajout de nouveau contenu via ajax. Je n'ai pas les erreurs de la console et il n'y a pas de questions si je visite l'URL directement.


Connexes:

  1. Forcer Script À Exécuter En AJAX Chargement de la Page - se Rapporte à l'un script spécifique. Je tiens à corriger (refire) tous les scripts, y compris les dynamiques de Cloudflare apps
  2. À l'aide de script jQuery Ajax dans Wordpress - Même que ci-dessus, cela ne se rapporte qu'à un seul script
  3. ajax du contenu chargé, le script ne s'exécute pas

Intro:

J'utilise Ajaxify Site WordPress(AWS) sur un site WordPress.

Le plugin vous permet de sélectionner un div par son id et extrait du nouveau contenu à l'intérieur qu' div à l'aide d'ajax

balisage html

<html>

<head></head> 

<body>
  <div id="page"> 
    <header></header>
    <main id="ajax"> <!-- This is what I want to ajaxify -->
      <div class="container">
        main page content
      </div> 
    </main> <!-- end of ajaxfied content  -->
    <footer></footer>
  </div> <!-- #page -->
</body>

</html>

Problème

Le plugin fonctionne et je reçois le contenu frais chargés et de style, mais il y a un problème. Certains de mes page des scripts et des appels de fonction sont en dehors de la div que j'utilise l'ajax. J'ai deux exemples

1 - Maçonnerie est chargé et a appelé à l' <footer>

<html>

<head></head> 

<body>
  <div id="page"> 
    <header></header>
    <main id="ajax"> <!-- This is what I want to ajaxify -->
      <div class="container">
        main page content
      </div>  
    </main>   <!-- end of ajaxfied content  -->
    <footer></footer> <!-- Masonry script is loaded and called here -->
  </div> <!-- #page -->
</body>

</html>

2 - Google maps appel est dans l' <head>

<html>

<head></head>  <!-- Google maps is called here -->

<body>
  <div id="page"> 
    <header></header>
    <main id="ajax"> <!-- This is what I want to ajaxify -->
      <div class="container">
        main page content
      </div>  
    </main>  <!-- end of ajaxfied content  -->
    <footer></footer> 
  </div> <!-- #page -->
</body>

</html>

Ce sont juste deux exemples. Il en existe d'autres dans d'autres endroits. Comme vous pouvez le dire, ces scripts ne seront pas ré-disant que la seule chose qui recharge sur la page d' <main id="ajax">. Alors que le nouveau contenu à l'intérieur d' <main> est-il, certains des scripts nécessaires pour rendre correctement ne sont pas re-appelé et je me retrouve avec des éléments manquants / cassé mise en page.


Je ne suis pas le seul qui a été confronté à ce problème; un rapide coup d'oeil au plugin forum de support sur wordpress.org montre que ce problème est courant.

Note: je ne voudrais pas essayer de résoudre ce problème si le plugin a beaucoup d'autres questions. Il fonctionne pour moi, j'ai juste besoin de scripts pour le re-feu.

La réponse officielle est qu'il est possible de recharger / re-feu scripts en ajoutant la ligne suivante dans le plugin php les fichiers:

$.getScript(rootUrl + 'PATH TO SCRIPT');

Qui fonctionne. Il fonctionne bien. par exemple si j'ajoute

$.getScript(rootUrl + '/Assets/masonry.js');

Puis la maçonnerie les appels de la fonction re-déclenché quand la ajaxed contenu est récupéré, même si masonry.js est chargé à l'extérieur de la ajaxed div

Je vous renvoie à la plugin fichiers sur github pour plus de clarté sur ce que le correctif ne fait (je ne peux pas donner un sens à ce qui arrive quand les $.getScript est utilisé)


En résumé

L'officiel correctif fonctionne très bien si vous avez 3-4 scripts qui doivent être re-tiré sur ajaxed de contenu.

Cela ne fonctionne pas pour mon objectif, car

  1. il est trop rigide et codée en dur
  2. Certains scripts sont ajoutés à la page dynamiquement via Cloudflare apps

Une solution possible pourrait impliquer l'ajout d'un événement imite l'élément déclencheur qui provoque les scripts de feu au bas de la ajaxed div

Question:

Comment puis-je la force de tous les scripts - y compris dynamiquement ajoutés ceux - re-le-feu lorsque seule une partie de la page a été rechargée via ajax?


Notes:

  1. Je suis en train d'essayer d'éviter d'appeler des scripts un par un, en tant que nécessiterait la connaissance de leurs appels avant de la main. Je suis probablement la façon de parler-dessus de ma tête , mais...

    Je suis en train d' imiter le chargement de la page et / ou le document de prêt des événements au cours de laquelle la plupart conditionnelle scripts sont tirés (corrigez-moi si je me trompe) - à la fin de l' <main> dans mon code html lorsque de nouvelles ajaxed contenu est ajouté, mais sans affecter le document lorsque la page est chargée via l'aide de l'url directement...ou toute autre méthode similaire.

  2. Juste pour un peu de contexte, voici une liste de certains des écouteurs d'événement sur la page alors que le plugin est désactivé. Je sais il y a des choses là-dedans que je n'aurai pas à déclencher. Je viens d'ajouter cette référence. Aussi, veuillez noter que ceci est un échantillon prélevé à partir de l'une des pages. d'autres pages qui peuvent différer.

DOMContentLoaded
beforeunload
blur
click
focus
focusin
focusout
hashchange
keydown
keyup
load
message
mousedown
mousemove
mouseout
mouseover
mouseup
mousewheel
orientationchange
readystatechange
resize
scroll
submit
touchscreen
unload

15voto

cjg Points 2129

La solution que vous choisissez ici devront dépendre de la façon dont les scripts sont initialisés. Il ya un couple commun possibilités:

  1. Le script d'actions sont évoquées immédiatement après le chargement du script. Dans ce cas, le script devrait ressembler à quelque chose comme ceci:

    (function() {
         console.log('Running script...');
    })();
    
  2. Le script d'actions sont évoquées en réponse à certains événements (tels que le document soit prêt (JQuery) ou de la fenêtre onload (JavaScript) et des événements). Dans ce cas, le script devrait ressembler à quelque chose comme ceci:

    $(window).on('load', function() {
        console.log('Running script...');
    });
    

Certaines options pour ces deux hypothèses sont envisagées ci-dessous.

Pour les scripts qui s'exécutent immédiatement sur le chargement

Une option serait de tout simplement supprimer l' <script> éléments que vous souhaitez déclencher à partir du DOM et ensuite rattacher. Avec JQuery, vous pourriez faire

$('script').remove().appendTo('html');

Bien sûr, si l'extrait ci-dessus est lui-même, en <script> balise, puis vous allez créer une boucle infinie de constamment détacher et ré-attacher tous les scripts. En outre, il peut y avoir quelques scripts que vous ne voulez pas exécuter de nouveau. Dans ce cas, vous pouvez ajouter des classes pour les scripts pour les sélectionner soit positivement ou négativement. Par exemple,

// Positively select scripts with class 'reload-on-ajax'
$('script.reload-on-ajax').remove().appendTo('html');

// Negatively select scripts with class 'no-reload'
$('script').not('no-reload').remove().appendTo('html')

Dans votre cas, vous devez placer l'un des ci-dessus des extraits dans le gestionnaire d'événement pour l'AJAX d'achèvement. L'exemple suivant utilise un clic de bouton en lieu et place de l'AJAX d'achèvement de l'événement, mais le concept est le même (notez que cet exemple ne fonctionne pas bien dans le StackOverflow bac à sable, donc essayez de charger une page séparée pour le meilleur résultat):

<html>
  <head></head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

  <script class="reload-on-ajax">
    console.log('Script after head run.');
  </script>

  <body>
    <button id="reload-scripts-button">Reload Scripts</button>
  </body>

  <script class="reload-on-ajax">
    console.log('Script after body run.');
  </script>

  <script>
     $('#reload-scripts-button').click( () => $('script.reload-on-ajax').remove().appendTo('html') );
  </script>
</html>

Notez que si les scripts ne sont pas en ligne (par exemple, récupérés par l' src d'attribut), alors ils seront rechargées à partir du serveur ou récupérées à partir de la mémoire cache du navigateur, en fonction du navigateur et les paramètres. Dans ce cas, la meilleure approche est probablement pour supprimer tous les <script>s qui fonctionnent sur l'AJAX chargé de contenu et de charger/exécuter eux par l'intermédiaire de quelque chose comme du JQuery getScript() fonction de l'AJAX d'achèvement de gestionnaire d'événements. De cette façon, vous ne serez chargement/exécutant les scripts une fois au moment opportun (c'est à dire après le contenu AJAX est chargé):

// In AJAX success event handler
$.getScript('script1.js');
$.getScript('script2.js');

Un problème potentiel avec les deux variantes de cette approche est que le chargement asynchrone du script est soumis à un contre-restrictions origine. Donc, si les scripts sont hébergés sur un autre domaine et de la croix-origine des demandes ne sont pas autorisés, il ne fonctionnera pas.

Pour les scripts qui s'exécutent en réponse à un événement

Si les scripts sont déclenchées sur la fenêtre de la charge, alors vous pouvez simplement déclencher cet événement:

   $(window).trigger('load');

Malheureusement, si les scripts eux-mêmes l'utilisation de JQuery document prêt événement, alors je ne suis pas au courant d'un moyen facile de déclencher manuellement. Il est également possible que les scripts s'exécutent en réponse à un autre événement.

Évidemment, vous pouvez combiner les approches ci-dessus si nécessaire. Et, comme d'autres l'ont mentionné, s'il y a une initialisation des fonctions dans les scripts que vous pouvez simplement appeler, alors que c'est la façon la plus propre.

5voto

Benni Points 375

Si vous pouvez identifier un mondial de l'initialisation de la fonction ou du bloc de code dans vos scripts externes, vous pouvez prendre un coup d'oeil à la " ajaxComplete de l'événement. Vous pouvez placer ce code dans votre page de tête et de mettre l'initialisation des appels de fonction ou de blocs de code à l'intérieur de la ajaxComplete de rappel.

$(document).ajaxComplete(function(){
    module1.init();
    $('#my_id').module2_init({
        foo : 'bar',
        baz : 123
    });
});

Lorsque les scripts dont vous parlez n'ont pas facile à utiliser, l'exposé de l'initialisation des fonctions, mais l'initialisation d'eux-mêmes sur scriptload, je pense qu'il y aura pas de sortie de la boîte de la méthode qui fonctionne pour tous les scripts.

5voto

Nitin Yawalkar Points 106

Voici ce que vous pouvez essayer

La plupart des scripts comme la maçonnerie ou la Carte de Google sont mis à la ré-initialisation de la fenêtre de redimensionnement. Donc, si vous déclenchez l'événement resize après ajax complet, il vous aidera à re-feu ces scripts automatiquement.

Essayez le code suivant -

$( document ).ajaxComplete( function() {
    $( window ).trigger('resize');
} );

Cela va forcer les scripts à la ré-initialisation une fois ajax est complété comme il sera désormais déclencher l'événement resize après que le contenu est chargé.

4voto

Hitmands Points 1199

Une solution pourrait être la duplication de tous les scripts...

$(document).ajaxSuccess((event, xhr, settings) => {
  // check if the request is your reload content
  if(settings.url !== "myReloadedContentCall") {
    return;
  }

  return window
    .setTimeout(rejs, 100)
  ;
});

function rejs() {
  const scripts = $('script[src]');
  // or, maybe alls but not child of #ajax
  // const scripts = $('*:not(#ajax) script[src]');

  Array
    .prototype
    .forEach
    .call(scripts, (script, index) => {
      const $script = $(script);

      const s = $('<script />', {
        src: $script.attr('src')
      });  
      // const s = $script.clone(); // should also work

      return s
        .insertAfter($script)
        .promise()
        .then(() => $script.remove()) // finally remove it
      ;
    })
  ;

}

4voto

lscmaro Points 523

Peut-être risqué, mais vous devriez être capable d'utiliser DOMSubtreeModified sur votre <main> élément pour cette.

$('#ajaxed').bind('DOMSubtreeModified', function(){
  //your reload code
});

Ensuite, vous devriez être en mesure de simplement ajouter tous vos scripts de nouveau dans votre zone de rechargement

var scripts = document.getElementsByTagName('script');
for (var i=0;i<scripts.length;i++){
   var src = scripts[i].src;
   var sTag = document.createElement('script');
   sTag.type = 'text/javascript';
   sTag.src = src;
   $('head').append(sTag);

}

Une autre option pourrait être de créer votre propre écouteur d'événement et ont la même recharger le code.

$(document).on('ajaxContentLoaded', function(){//same reload code});

Ensuite, vous pouvez déclencher un événement dans le plugin une fois que le contenu a été mis à jour.

$(document).trigger('ajaxContentLoaded');

Ou peut-être une combinaison de modifier le plugin pour déclencher un écouteur et les ajouter à votre base de code pour ré-exécuter tout ce que vous sentez que vous avez besoin de la re-couru hors de cet auditeur, plutôt que de recharger quoi que ce soit.

$(document).on('ajaxContentLoaded', function(){
   //Javascript object re-initialization
   myObj.init();
   //Just a portion of my Javascript?
   myObj.somePortion();
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X