IFrame OnReadyStateChange function - javascript

I have an asp.webforms application and on page a i have a hidden div with progressbar and iframe. To iframe i try loaded form from another application on same domain.
<div id="pagePreview" style="display: none;">
<div class="progressBarWrapper" id="waitDialog" style="opacity:1;filter:alpha(opacity=100);display:none;">
<div class="progressBarDetail" style="margin-top:25%;">
<asp:Image ID="imgLoading" runat="server" ImageUrl="~/Images/wait.gif" />
</div>
</div>
<iframe id="previewContent" onreadystatechange="iframeLoaded(this);"></iframe>
</div>
On a click event i call a function to show this div in jqueryUI dialog and i Want show progressbar until the page in Iframe is not loaded.
var isClickedForDialog = false;
function iframeLoaded(args) {
if (args.readyState == "complete" && isClickedForDialog) {
var pagePreview = $('#pagePreview'); // dialog
var waitDialog = $('#waitDialog'); // progress
waitDialog.hide();
isClickedForDialog = false;
}
}
function showModalWindow(url, hideCloseButton) {
isClickedForDialog = true;
var previewContent = $('#previewContent'); // Iframe
var pagePreview = $('#pagePreview'); // dialog
var waitDialog = $('#waitDialog'); // progresss
waitDialog.show();
previewContent.attr('src', url);
pagePreview.dialog(
{
draggable: false,
resizable: false,
height: 764,
width: 1020,
modal: true,
close: function (event, ui) {
previewContent.attr('src', '');
},
open: function (event, ui) {
if (hideCloseButton) {
$(this).parent().children().children('.ui-dialog-titlebar-close').hide();
}
}
});
}
In IE everything works fine. The dialog box and progressbar displays and when the URL is loaded in an iframe, progressbar disappears and i see only webforms in IFrame.
But in FireFox and Chrome this does not work.
The browser ignores the onreadystatechange event. I tried to handle an event as following:
$('#previewContent').bind('onreadystatechange', iframeLoaded, false);
$('#previewContent').on('onreadystatechange', iframeLoaded);
but without success.
know how to solve this? thanks

I'm not sure if there's some specific reason why you're using onreadystatechange, but if you just want to know when the iframe is done loading, the load event will handle that.
$('#previewContent').on('load', iframeLoaded);

Adding the onreadystatechange attribute to an iframe tag as shown in the original question doesn't seem to do anything. Don't do this:
<iframe onreadystatechange="iframeReady(this);"></iframe>
Instead, grab a reference to the iframe element and add a DOMContentLoaded listener to its contentDocument property. Since your iframe might already be fully loaded, you should check its contentDocument's readyState and cancel the listener if the iframe isn't loaded yet. Finally, some browsers - namely Firefox - don't currently emit a DOMContentLoaded event from iframes, so for a fallback you could add a load listener on the iframe's contentWindow property, or the iFrame itself.
function listenForIframeReady() {
if (iframe.contentDocument.readyState === "interactive" || iframe.contentDocument.readyState === "complete") {
iframeReady();
} else {
iframe.contentDocument.addEventListener('DOMContentLoaded', iframeReady);
iframe.contentWindow.addEventListener('load', iframeReady);
iframe.addEventListener('load', iframeReady);
}
}
function iframeReady() {
console.log('iframe is ready');
iframe.contentDocument.removeEventListener('DOMContentLoaded', iframeReady);
iframe.contentWindow.removeEventListener('load', iframeReady);
iframe.removeEventListener('load', iframeReady);
}
var iframe = document.querySelector('iframe');
listenForIframeReady();

Related

Call user defined jQuery function with JS

I use a jQuery window libray https://github.com/humaan/Modaal
which triggers events this way $("class of element").modaal({arg1, arg2,...});
--- I updated my question here to make it more general and used an iframe / Html instead of an external svg ---
To trigger an element e.g. in an external Html which is loaded within an iframe, I applied the following code to the iframe:
<iframe src="External.html" id="mainContent" onload="access()"></iframe>
which calls this function:
function access() {
var html = document.getElementById("mainContent").contentDocument.getElementById("IDofDIVelement");
html.addEventListener('click', function() {clicker();});
}
function clicker()
{
// console.log('hooray!');
$("#mainContent").contents().find("IDofDIVelement").modaal({});
//return false;
}
Actually it will only work on every second click. Any idea what I did not consider properly?
Best
You do not need to wait windows loading but iframe only:
$(function() {
$("#mainContent").bind("load",function(){
var myIframeElement = $(this).contents().find(".modaal");
myIframeElement.modaal({
content_source: '#iframe-content',
type: 'inline',
});
});
});
The reason why it did not work was that the iframe was not completely loaded, while jQuery tried to attach the function. As $(document).ready(function(){} did not work, the workaround was to initialize it with
$( window ).on( "load",function() {
$("#mainContent").contents().find("IDofDIVelement").modaal({});
});
This worked properly to attach the functionallity to an element within the iframe.
Actually modaal will vanish the envent handler after the overlay was opened and closed again.
So maybe someone wants to trigger an iframe element for modaal, too, here is a setup which would solve this issue.
(It can be optimised by #SvenLiivaks answer):
$(window).on("load", function() {
reload();
});
function reload() {
var length = $("#iframeID").contents().find("#IDofDIVelement").length;
// The following check will return 1, as the iframe exists.
if (length == 0) {
setTimeout(function() { reload() }, 500);
} else {
$("#iframeID").contents().find("#IDofDIVelement").modaal({
content_source: '#modalwrapper',
overlay_close: true,
after_close: function reattach() {
reload();
}
});
}
}

Difficulty attaching event handler to dynamically generated modal window elements

This question is an ongoing learning / discovery of these three questions. This issue for me started here:
First Post
Second Post
Now this post is regarding #StephenMuecke post about attaching the event handler dynamically. This was new to me so I had to read up but now I see that it does make sense.
Well after reading documentation and numerous SO posts I still can't seem to get the click event handler to fire??
This time I decided to take a different approach. I created a jsfiddle demonstrating the problem. http://jsfiddle.net/ramjet/93nqs040/17/
However the jsfiddle I had to change somewhat from reality to get it to work within their framework. Below is the actual code.
Parent Window script that launches modal...the alert Bound does fire.
<script>
$(document).ready(function ()
{
$("#new").click(function (e)
{
e.preventDefault();
var ischanging = false;
var financierid = 0;
var detailsWindow = $("#window").data("kendoWindow");
if (!detailsWindow)
{
// create a new window, if there is none on the page
detailsWindow = $("#window")
// set its content to 'loading...' until the partial is loaded
.html("Loading...")
.kendoWindow(
{
modal: true,
width: "800px",
height: "400px",
title: "#T("...")",
actions: ["Close"],
content:
{
url: "#Html.Raw(Url.Action("ActionName", "Controller"))",
data: { financierId: financierid, isChanging: ischanging }
}
})
.data("kendoWindow").bind('refresh', function (e)
{
alert('Bound');
$('document').on("click", "#save", function () { alert("i work");});
}).center();
}
detailsWindow.open();
});
</script>
The modal full html I didn't think was needed but if it is I will update it. This is just the element I am trying to dynamically bind to.
<input type="button" id="save" style="margin-right:10px;" value="Save Record" />
document doesn't need quotes:
$(document).on("click", "#save", function () { alert("i work");});
"document" searches for an element of document, not the actual document
$("document").length; //0
$(document).length; //1

PJAX/DJAX- rerun scripts after pjax load

I'm using RequireJS to structure my JS and DJAX (basically PJAX) as a way to dynamically load content without a full page reload.
The issue I have is that after DJAX has finished loading the content I need to rerun my scripts (e.g. a script that adds multiple images into a carousel) so that the new page renders correctly. I thought the best way to do this would be to simply rerun the function I'm running on $(document).ready(); but I'm getting this output in the console:
Uncaught TypeError: Cannot read property 'djaxLoad' of undefined
which is referring to this line in load-posts.js
bootstrap.init();
I'm guessing I'm writing something incorrectly.
Here is bootstrap.js which is my main file which fires on document.ready and initialises all my modules
require(['base/responsive', 'base/main-menu', 'base/social-share', 'base/randomise-colours', 'base/infinite-scroll', 'base/load-posts', 'base/image-fade', 'base/carousel', 'base/misc'],
function(responsive, main_menu, social_share, randomise_colours, infinite_scroll, load_posts, image_fade, carousel, misc) {
var $ = jQuery;
function djaxLoad() {
//If page has JS (detected with Modernizr) then hide content until the
//doc is ready to avoid flash of unstyled content
$('#djax-container').css('display', 'block');
main_menu.init();
social_share.init();
randomise_colours.init();
load_posts.init();
image_fade.init();
infinite_scroll.init();
carousel.init();
misc.init();
responsive.init();
}
$(document).ready(djaxLoad);
}
);
And this is load-posts.js which handles DJAX for me. DJAX works, I just need to get the scripts to fire again.
define(['djax', 'base/bootstrap'], function(djax, bootstrap) {
var $ = jQuery,
$body = $('body');
return {
init: function() {
if($body.length >= 1) {
this.setUp();
} else {
return false;
}
},
setUp: function() {
this.pjaxLinks();
},
pjaxLinks: function() {
//Initialise DJAX, but stop it from running on pagination links (URL is /page...)
$('body').djax('.updateable', ['page']);
//When clicking a djax link
$(window).bind('djaxClick', $.proxy(function() {
this.addLoader();
},this));
//When the new content has loaded in
$(window).bind('djaxLoad', $.proxy(function() {
this.removeLoader();
},this));
},
addLoader: function() {
$body.addClass('loader-visible');
},
removeLoader: function() {
$body.removeClass('menu-visible');
$('html, body').scrollTop(0);
function removeLoaderDelay() {
$body.removeClass('loader-visible');
bootstrap.djaxLoad();
}
setTimeout(removeLoaderDelay, 1000);
}
};
});
The djaxClick function runs on a link click, and the djaxLoad function runs after the content has been loaded in. I'm adding a loader overlay to the page, then removing it after the content has loaded in.
A bit late but for future reference: In the documentation at https://github.com/beezee/djax you'll find the djaxLoad-event. This is specifically made for your usecase. You can use it as follows:
$(window).bind('djaxLoad', function(e, data) {
// your scripts to run on ajax-calls
});
The site further explains: "the data object passed with the event contains the requested url, the page title for the requested page, and the contents of the requested page as a string".
$(window).bind('djaxLoad', function(e, data) {
var responseObj = $('<div>'+data.response+'</div>');
//do stuff here
});

Dynamically resizing an iframe that uses AJAX

I am attempting to dynamically resize an iframe. This wasn't too hard, until I changed the iframe page to use AJAX with jQuery. I am attaching a function to the iframe body's resize event that should resize the iframe as well. It seems that after it started using AJAX it would no longer trigger the resize event.
Here is the code I have in the parent site:
$(function(){
var iframe = $('#myiframe');
iframe.load( function() {
var iframe_content = iframe.contents().find('#content');
iframe_content.resize( function() {
var elem = $(this);
var newHeight = elem.height();
// Resize the iframe.
iframe.css({ height: newHeight });
});
// Resize the iframe immediately
iframe_content.resize();
});
});
Here is the AJAX form in the iframe site:
<form onsubmit="jQuery.ajax({type: 'GET',
data: $(this).serialize(),
url: '/employeedirectory/employee/ajaxUpdate',
success:function( data, textStatus ) {
$('#results').html(data);
// Go to the parent document, find the content div, and call its resize event
$(document, parent.window.document).contents().find('#myiframe').contents().find('#content').resize();
},
error: function( XMLHttpRequest, textStatus, errorThrown ) {} });
return false;"
id="searchForm">
</form>
If I run $('#myiframe').contents().find('#content').resize() on the parent site to force the resize event then it works just fine. But it doesn't appear that it is calling that onsuccess like I want. Does anyone have any ideas?

How do I detect if a javascript constructor already been run?

I'm using the jquery-tools tabs and carousel in a page I'm working on. The carousel is embedded within a tab, and the tab is loaded in a beforeClick callback.
Normally, the carousel is initialized in the document ready function like so:
$(function() {
// initialize scrollable
$("div.scrollable").scrollable({
size: 3,
clickable: true,
loop: false
}).mousewheel();
This doesn't work when the carousel is loaded via beforeClick, because it when the DOM is ready, this tab hasn't been loaded yet.
$("ul.tabs").tabs("div.panes > div", {
initialIndex: 0,
onBeforeClick: function(event, i) {
// get the pane to be opened
var pane = this.getPanes().eq(i);
var src = this.getTabs().eq(i).attr("href");
var langPattern = "/^" + getLang() + '/';
var forceReload = false;
if (src.match(langPattern) == null)
{
src = getLang() + "/" + src;
forceReload = true;
}
if (pane.is(":empty") || forceReload) {
// load it with a page specified in the tab's href attribute
pane.load(src);
// initialize scrollable - ONLY SHOULD BE DONE ONCE
$("div.scrollable").scrollable({
size: 3,
clickable: true,
loop: false
}).mousewheel();
}
}
}).history();;
My question is a two-parter:
First, is there an event I can add a handler to to initialize the scrollable when it is first loaded?
Second, if there isn't, is there a way I can find out if the scrollable has been constructed yet?
The idea behind this code is to load localized html fragments based on the user's language selection. This is for a catalog on a CD, not online.
You might want to check out the jQuery live event. This event matches all current and future DOM matches.
EDIT 1
You want to bind to div.scrollable's onload event, correct?
$('div.scrollable').live('load', function() {
// etc.
});
I solved my problem by attaching a callback to the load call:
pane.load(src, "", function(){
$("div.scrollable").scrollable({
size: 3,
clickable: true,
loop: false
}).mousewheel();
});

Categories