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?
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.
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.
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.
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);
});
});
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.
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().
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";
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');
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>