javascript - how - jQuery. listo en un iframe insertado dinĂ¡micamente
iframe ready (9)
Estamos utilizando jQuery thickbox para mostrar dinámicamente un iframe cuando alguien hace clic en una imagen. En este iframe, estamos utilizando galleria una biblioteca de JavaScript para mostrar varias imágenes.
El problema parece ser que $(document).ready
en el iframe parece haberse activado demasiado pronto y el contenido del iframe aún no está cargado, por lo que el código galleria no se aplica correctamente en los elementos del DOM. $(document).ready
parece usar el estado de iframe parent ready para decidir si el iframe está listo.
Si extraemos la función llamada por documento preparado en una función separada y la llamamos después de un tiempo de espera de 100 ms. Funciona, pero no podemos arriesgarnos en producción con una computadora lenta.
$(document).ready(function() { setTimeout(ApplyGalleria, 100); });
Mi pregunta: ¿a qué evento de jQuery nos deberíamos enlazar para poder ejecutar nuestro código cuando el iframe dinámico esté listo y no solo como uno de los padres?
Básicamente lo que otros ya han publicado, pero en mi humilde opinión un poco más limpio:
$(''<iframe/>'', {
src: ''https://example.com/'',
load: function() {
alert("loaded")
}
}).appendTo(''body'');
En IFrames generalmente resuelvo este problema poniendo un pequeño script al final del bloque:
<body>
The content of your IFrame
<script type="text/javascript">
//<![CDATA[
fireOnReadyEvent();
parent.IFrameLoaded();
//]]>
</script>
</body>
Esto funciona la mayor parte del tiempo para mí. A veces, la solución más sencilla e ingenua es la más adecuada.
Encontré la solución al problema.
Cuando hace clic en un enlace de la caja gruesa que abre un marco flotante, inserta un marco flotante con una identificación de TB_iframeContent.
En lugar de confiar en el evento $(document).ready
en el código iframe, solo tengo que vincular al evento load del iframe en el documento padre:
$(''#TB_iframeContent'', top.document).load(ApplyGalleria);
Este código está en el iframe pero se une a un evento de un control en el documento principal. Funciona en FireFox y IE.
Este fue el problema exacto que encontré con nuestro cliente. Creé un pequeño plugin jquery que parece funcionar para la preparación del iframe. Utiliza el sondeo para comprobar el documento iframe readyState combinado con el url interno del documento combinado con la fuente del iframe para asegurarse de que el iframe de hecho está "listo".
El problema con "onload" es que necesita acceder al iframe real que se está agregando al DOM; si no lo hace, debe intentar atrapar la carga del iframe que, si está en caché, es posible que no. Lo que necesitaba era un script que se pudiera llamar en cualquier momento, y determinar si el iframe estaba o no "listo".
Aquí está la pregunta:
Santo grial para determinar si el iframe local se ha cargado o no
y aquí está el jsfiddle que eventualmente se me ocurrió.
https://jsfiddle.net/q0smjkh5/10/
En el jsfiddle anterior, estoy esperando que onload anexe un iframe al dom, y luego verifico el estado de documento interno de iframe, que debe ser de dominio cruzado porque apunta a wikipedia, pero Chrome parece informar "completo". A continuación, se llama al método Iadyady del complemento cuando el iframe está listo. La devolución de llamada intenta verificar nuevamente el estado listo del documento interno, esta vez informando una solicitud de dominio cruzado (que es correcto), de todos modos parece funcionar para lo que necesito y espero que ayude a otros.
<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>
Estoy cargando el PDF con jQuery ajax en el caché del navegador. Luego creo elementos integrados con datos que ya están en la memoria caché del navegador. Supongo que funcionará con iframe también.
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();
}
});
También debe configurar sus encabezados http correctamente.
HttpContext.Response.Expires = 1;
HttpContext.Response.Cache.SetNoServerCaching();
HttpContext.Response.Cache.SetAllowResponseInBrowserHistory(false);
HttpContext.Response.CacheControl = "Private";
Prueba esto,
<iframe id="testframe" src="about:blank" onload="if (testframe.location.href != ''about:blank'') testframe_loaded()"></iframe>
Todo lo que necesita hacer entonces es crear la función JavaScript testframe_loaded ().
Respondí una pregunta similar (ver la devolución de llamada de Javascript cuando se terminó de cargar IFRAME? ). Puede obtener control sobre el evento de carga iframe con el siguiente código:
function callIframe(url, callback) {
$(document.body).append(''<IFRAME id="myId" ...>'');
$(''iframe#myId'').attr(''src'', url);
$(''iframe#myId'').load(function() {
callback(this);
});
}
Al tratar con iframes, encontré lo suficientemente bueno para usar el evento de carga en lugar del evento listo para el documento.
Siguiendo la idea de DrJokepu y David Murdoch, implementé una versión más completa. Requiere jQuery tanto en el elemento principal como en el iframe y el iframe para estar bajo su control.
código 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");
});
});
}
código de prueba para padres:
$(function(){
$("iframe").on("iframeloading iframeready iframeloaded iframebeforeunload iframeunloaded", function(e){
console.log(e.type);
});
});
Usando jQuery 1.3.2 lo siguiente funcionó para mí:
$(''iframe'').ready(function() {
$(''body'', $(''iframe'').contents()).html(''Hello World!'');
});
REVISIÓN:! En realidad, el código anterior a veces parece que funciona en Firefox, nunca parece que funcione en Opera.
En cambio, implementé una solución de sondeo para mis propósitos. Simplificado abajo se ve así:
$(function() {
function manipIframe() {
el = $(''body'', $(''iframe'').contents());
if (el.length != 1) {
setTimeout(manipIframe, 100);
return;
}
el.html(''Hello World!'');
}
manipIframe();
});
Esto no requiere código en las páginas del iframe llamado. Todo el código reside y se ejecuta desde el marco / ventana principal.