jQuery.prêt dans une iframe dynamiquement insérée

nous utilisons jQuery thickbox 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 tiré trop tôt et le contenu de l'iframe n'est même pas encore chargé, donc le code galleria n'est pas appliqué correctement sur les éléments DOM. $(document).ready semble utilisez l'état parent prêt iframe pour décider si l'iframe est prêt.

si nous extrayons la fonction appelée par document prêt dans une fonction séparée et l'appelons après un délai 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 devrions-nous nous lier pour pouvoir exécuter notre code lorsque l'iframe dynamique est prête et pas seulement un parent?

176
demandé sur Peter Mortensen 2008-10-15 19:09:22

9 réponses

j'ai répondu à une question similaire (voir appel Javascript quand IFRAME est terminé chargement? ). Vous pouvez obtenir le contrôle de l'événement de charge 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);
    });
}

en traitant les iframes, j'ai trouvé assez bon pour utiliser load event au lieu de document ready event.

282
répondu Pier Luigi 2017-05-23 12:34:12

en utilisant jQuery 1.3.2 les suivants ont travaillé pour moi:

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

révision:! En fait, le code ci-dessus semble parfois fonctionner dans Firefox, jamais dans Opera.

au lieu de cela j'ai implémenté une solution de sondage pour mes besoins. Simplifié vers le bas il 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 iframe appelées. Tout le code réside et s'exécute à partir du cadre/fenêtre parent.

27
répondu Már Örlygsson 2011-03-28 10:25:09

dans IFrames Je résous habituellement ce problème en mettant un petit script à la toute fin du bloc:

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

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

14
répondu Tamas Czinege 2008-10-15 15:54:38

suite à L'idée de Drjokepu et David Murdoch j'ai mis en place une version plus complète. Il exige jQuery sur le parent et iframe et l'iframe d'être dans 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 d'essai parent:

$(function(){
    $("iframe").on("iframeloading iframeready iframeloaded iframebeforeunload iframeunloaded", function(e){
        console.log(e.type);
    });
});
8
répondu Ricardo Freitas 2013-04-30 01:49:51

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 compter sur l'événement $(document).ready dans le code iframe, je dois juste me lier à l'événement de charge 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.

4
répondu EtienneT 2011-03-04 16:42:59

Essayez cette,

<iframe id="testframe" src="about:blank" onload="if (testframe.location.href != 'about:blank') testframe_loaded()"></iframe>

tout ce que vous devez faire alors est de créer la fonction JavaScript testframe_loaded().

1
répondu Danny G 2011-05-30 21:38:32

je charge le PDF avec jquery ajax dans la cache du navigateur. Ensuite, je crée l'élément intégré avec des données déjà dans le cache du navigateur. Je suppose que ça marchera aussi avec iframe.


var url = "http://example.com/my.pdf";
// show spinner
$.mobile.showPageLoadingMsg('b', note, false);
$.ajax({
    url: url,
    cache: true,
    mimeType: 'application/pdf',
    success: function () {
        // display cached data
        $(scroller).append('<embed type="application/pdf" src="' + url + '" />');
        // hide spinner
        $.mobile.hidePageLoadingMsg();
    }
});

vous devez configurer correctement vos en-têtes http.


HttpContext.Response.Expires = 1;
HttpContext.Response.Cache.SetNoServerCaching();
HttpContext.Response.Cache.SetAllowResponseInBrowserHistory(false);
HttpContext.Response.CacheControl = "Private";
1
répondu Pavel Savara 2012-08-16 14:32:45

essentiellement ce que d'autres ont déjà posté mais IMHO un peu plus propre:

$('<iframe/>', {
    src: 'https://example.com/',
    load: function() {
        alert("loaded")
    }
}).appendTo('body');
1
répondu udondan 2017-08-01 14:19:59

C'était exactement le problème que j'ai rencontré avec notre client. J'ai créé un petit plugin jquery qui semble fonctionner pour la préparation iframe. Il utilise le sondage pour vérifier le document iframe readyState combiné avec l'url du document interne combiné avec la source iframe pour s'assurer que l'iframe est en fait "prêt".

le problème avec "onload" est que vous avez besoin d'accéder à l'iframe réelle étant ajouté au DOM, si vous ne le faites pas, alors vous devez essayer d'attraper le chargement iframe qui si elle est mise en cache, alors vous ne pouvez pas. Ce dont j'avais besoin, c'était d'un script qui pourrait être appelé n'importe quand, et qui déterminerait si l'iframe était "prête" ou non.

Voici la question:

Saint Graal pour déterminer si iframe locale a chargé

et voici le jsfiddle que j'ai finalement inventé.

https://jsfiddle.net/q0smjkh5/10 /

dans le jsfiddle ci - dessus, j'attends onload pour ajouter une iframe au dom, puis vérifier l'état prêt du document interne d'iframe - qui devrait être cross domain parce qu'il est pointé sur wikipedia-mais Chrome semble rapporter"complet". La méthode iready du plug-in est alors appelée lorsque l'iframe est en fait prête. Le callback essaie de vérifier à nouveau l'état de préparation du document interne - cette fois en rapportant une requête de domaine croisée (qui est correcte) - quoi qu'il en soit il semble fonctionner pour ce que je besoin et espoir qu'il aide les autres.

<script>
  (function($, document, undefined) {
    $.fn["iready"] = function(callback) {
      var ifr = this.filter("iframe"),
          arg = arguments,
          src = this,
          clc = null, // collection
          lng = 50,   // length of time to wait between intervals
          ivl = -1,   // interval id
          chk = function(ifr) {
            try {
              var cnt = ifr.contents(),
                  doc = cnt[0],
                  src = ifr.attr("src"),
                  url = doc.URL;
              switch (doc.readyState) {
                case "complete":
                  if (!src || src === "about:blank") {
                    // we don't care about empty iframes
                    ifr.data("ready", "true");
                  } else if (!url || url === "about:blank") {
                    // empty document still needs loaded
                    ifr.data("ready", undefined);
                  } else {
                    // not an empty iframe and not an empty src
                    // should be loaded
                    ifr.data("ready", true);
                  }

                  break;
                case "interactive":
                  ifr.data("ready", "true");
                  break;
                case "loading":
                default:
                  // still loading
                  break;   
              }
            } catch (ignore) {
              // as far as we're concerned the iframe is ready
              // since we won't be able to access it cross domain
              ifr.data("ready", "true");
            }

            return ifr.data("ready") === "true";
          };

      if (ifr.length) {
        ifr.each(function() {
          if (!$(this).data("ready")) {
            // add to collection
            clc = (clc) ? clc.add($(this)) : $(this);
          }
        });
        if (clc) {
          ivl = setInterval(function() {
            var rd = true;
            clc.each(function() {
              if (!$(this).data("ready")) {
                if (!chk($(this))) {
                  rd = false;
                }
              }
            });

            if (rd) {
              clearInterval(ivl);
              clc = null;
              callback.apply(src, arg);
            }
          }, lng);
        } else {
          clc = null;
          callback.apply(src, arg);
        }
      } else {
        clc = null;
        callback.apply(this, arguments);
      }
      return this;
    };
  }(jQuery, document));
</script>
0
répondu Jon Freynik 2017-05-23 12:02:12