191 votes

jQuery .ready dans une iframe insérée dynamiquement

Nous utilisons jQuery boîte épaisse pour afficher dynamiquement une iframe lorsque quelqu'un clique sur une image. Dans cette iframe, nous utilisons galleria une bibliothèque javascript pour afficher plusieurs images.

Le problème semble être que $(document).ready dans l'iframe semble être déclenché trop tôt et le contenu de l'iframe n'est même pas encore chargé, donc le code de la galleria n'est pas appliqué correctement sur les éléments du DOM. $(document).ready semble utiliser l'état ready du parent de l'iframe pour décider si l'iframe est prêt.

Si nous extrayons la fonction appelée par le document prêt dans une fonction séparée et l'appelons après un délai d'attente de 100 ms. Cela fonctionne, mais nous ne pouvons pas prendre le risque en production avec un ordinateur lent.

$(document).ready(function() { setTimeout(ApplyGalleria, 100); });

Ma question : quel événement jQuery doit-on lier pour pouvoir exécuter notre code lorsque l'iframe dynamique est prêt et pas seulement lorsqu'il est parent ?

1 votes

Et vous confirmez que Galleria fonctionne lorsque vous le chargez directement au lieu de passer par un iframe, correct ?

0 votes

Oui, galleria fonctionne parfaitement lorsque nous l'utilisons directement dans une page normale.

0 votes

294voto

Pier Luigi Points 4428

J'ai répondu à une question similaire (voir Callback Javascript lorsque le chargement de l'IFRAME est terminé ? ). Vous pouvez obtenir le contrôle de l'événement de chargement de l'iframe avec le code suivant :

function callIframe(url, callback) {
    $(document.body).append('<IFRAME id="myId" ...>');
    $('iframe#myId').attr('src', url);

    $('iframe#myId').load(function() {
        callback(this);
    });
}

Pour les iframes, j'ai trouvé qu'il était suffisant d'utiliser l'événement load au lieu de l'événement document ready.

17 votes

Ne devriez-vous pas définir l'événement de chargement avant d'appeler l'attr('src') ?

15 votes

Non, cela n'a pas d'importance. L'événement de chargement ne se déclenchera pas avant la prochaine boucle d'événements, au minimum.

29 votes

L'événement load ne fonctionnera pas pour les iframes qui sont utilisées pour le téléchargement. comme <iframe src="mon.pdf"/>

31voto

En utilisant jQuery 1.3.2, j'ai obtenu les résultats suivants :

$('iframe').ready(function() {
  $('body', $('iframe').contents()).html('Hello World!');
});

RÉVISION : ! En fait, le code ci-dessus semble parfois fonctionner dans Firefox, mais jamais dans Opera.

Au lieu de cela, j'ai mis en place une solution de sondage pour mes besoins. En simplifiant, cela ressemble à ceci :

$(function() {
  function manipIframe() {
    el = $('body', $('iframe').contents());
    if (el.length != 1) {
      setTimeout(manipIframe, 100);
      return;
    }
    el.html('Hello World!');
  }
  manipIframe();
});

Cela ne nécessite pas de code dans les pages appelées iframe. Tout le code réside et s'exécute dans le cadre/fenêtre parent.

15voto

Tamas Czinege Points 49277

Dans les IFrames, je résous généralement ce problème en plaçant un petit script à la toute fin du bloc :

<body>
The content of your IFrame
<script type="text/javascript">
//<![CDATA[
   fireOnReadyEvent();
   parent.IFrameLoaded();
//]]>
</script>
</body>

Cela fonctionne la plupart du temps pour moi. Parfois, la solution la plus simple et la plus naïve est la plus appropriée.

4 votes

+1 Cette solution fonctionne très bien pour moi ! Un excellent ajout est que vous pouvez atteindre le bouton de l'interrupteur. parent pour obtenir une copie de jQuery et utiliser parent.$(document).ready(function(){ parent.IFrameLoaded( ); }); pour initialiser l'iframe.

9voto

Ricardo Freitas Points 71

Suite à l'idée de DrJokepu et David Murdoch, j'ai implémenté une version plus complète. Il s'agit de nécessite jQuery sur le parent et l'iframe et l'iframe doit être sous votre contrôle.

code iframe :

var iframe = window.frameElement;

if (iframe){
    iframe.contentDocument = document;//normalization: some browsers don't set the contentDocument, only the contentWindow

    var parent = window.parent;
    $(parent.document).ready(function(){//wait for parent to make sure it has jQuery ready
        var parent$ = parent.jQuery;

        parent$(iframe).trigger("iframeloading");

        $(function(){
            parent$(iframe).trigger("iframeready");
        });

        $(window).load(function(){//kind of unnecessary, but here for completion
            parent$(iframe).trigger("iframeloaded");
        });

        $(window).unload(function(e){//not possible to prevent default
            parent$(iframe).trigger("iframeunloaded");
        });

        $(window).on("beforeunload",function(){
            parent$(iframe).trigger("iframebeforeunload");
        });
    });
}

code de test parent :

$(function(){
    $("iframe").on("iframeloading iframeready iframeloaded iframebeforeunload iframeunloaded", function(e){
        console.log(e.type);
    });
});

0 votes

Pour une raison quelconque, l'utilisation de $(iframe).ready(function...) dans le parent ne fonctionne pas pour moi. Il semblait que la fonction de rappel était exécutée avant que le dom iframe soit prêt. L'utilisation de cette méthode a très bien fonctionné !

4voto

EtienneT Points 1552

J'ai trouvé la solution au problème.

Lorsque vous cliquez sur un lien thickbox qui ouvre une iframe, il insère une iframe avec un id de TB_iframeContent.

Au lieu de s'appuyer sur le $(document).ready dans le code de l'iframe, il me suffit de me lier à l'événement de chargement de l'iframe dans le document parent :

$('#TB_iframeContent', top.document).load(ApplyGalleria);

Ce code est dans l'iframe mais se lie à un événement d'un contrôle dans le document parent. Il fonctionne dans FireFox et IE.

9 votes

Vous avez trouvé la solution ? On dirait que Pier l'a déjà postée. Que vous l'ayez trouvée par vous-même ou non, l'étiquette voudrait que vous acceptiez sa réponse, récompensant ainsi le temps qu'il a passé à vous répondre.

0 votes

La différence entre la solution de Pier et celle-ci (et ce qui manquait dans mon code) est le contexte top.document qui me permet d'avoir du code à l'intérieur de l'iframe soit capable de dire quand l'iframe a été chargé. (Bien que load a été déprécié depuis cette réponse, et doit être remplacé par on("load") .)

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