Iframe attribute onload is called many times - javascript

I have an iframe that needs to rezise it's height each time it is loaded, I tried so many examples but all of them worked fine on IE and Chrome but not FireFox, until I tried this one and it works on everything
function autoResize() {
var subscriptionFrame = jQuery("#frame_name_here");
var innerDoc = (subscriptionFrame.get(0).contentDocument) ? subscriptionFrame
.get(0).contentDocument
: subscriptionFrame.get(0).contentWindow.document;
if (innerDoc.body.scrollHeight == 0)
innerDoc.location.reload(true);
subscriptionFrame.height(innerDoc.body.scrollHeight + 10);
}
<iframe src="uploadFile.xhtml" class="upload-iframe"
id="frame_name_here" onload="autoResize();"></iframe>
But there is a problem that this script calls the onload many times (recursive) , any idea why?

I found an answer to this , the iframe part is displayed as none, that doesn't mean it is not in the Dom tree, that is why the recursive part happen, as the iframe in this case didn't get any height until the iframe is displayed and the content of the height is read by the resize function.So to work around this, instead of display:none, I made the iframe part not rendered in the dom tree until certain action, so with this action the resize method will read the content only once.

Related

Getting undefined when trying to get .offset().top value of element in iframe

I am running in to an issue with Firefox and Safari where when trying to get the .offset().top value from an element in an iframe, I am getting undefined back when trying to get this value. This seems to work fine in Chrome, Edge and IE, but not in Firefox or Safari.
Here's the URL:
https://twlatl.github.io/styleguide/
When you click the navigation in Firefox, you'll see the error in the console.
TypeError: this.$iframeContent.find(...).offset(...) is undefined
The block that is causing problems is here:
gotoAnchor: function($elem) {
window.location.hash = '!' + $elem.attr('href').replace('#', '');
this.top = this.$iframeContent.find('h1' + $elem.attr('href')).offset().top;
this.$iframeContent.find('html, body').animate({
scrollTop: this.top
}, 800);
},
Removing the .offset().top from the element removes the error, but also removes the ability to scroll to that portion of the page.
I've tried wrapping this variable in an .on() method to check that the iframe is fully loaded first, but that doesn't work.
Try this (you can restructure to meet your needs)
var iframe = document.body.querySelector('.hgt-iframe-wrapper > iframe')
var iframeBody = iframe.contentDocument.body
var sectionHeader = iframeBody.querySelector($elem.attr('href'))
if( sectionHeader ){
sectionHeader.scrollIntoView()
}
Note: you'll get an error with this ^ because ID's aren't allowed to start with numbers. Change the section header ID's to start with a letter and it will work
Update
Ah, your problem is your are accessing the content of your iframe before its loaded. If you refresh sometimes it loads fast enough and your menu works. You can see in the screenshot below that the iframe was not loaded fast enough and so this.$iframeContent is effectively empty (no <div>s returned)

getElementById from parent works for Firefox not for IE

I am trying to access an element in my Edge Animate animation (which is a menu bar) from the parent document. The element has an onClick event which is triggered depending on the #bookmark in the URL of the parent web page. My code works perfectly in Firefox but does not work in Internet Explorer(10). IE is unable to see any elements within the 'Stage' div whereas Firefox can.
This is the JavaScript code on my parent page: -
<script language='javascript'>
var thisPage = window.location.pathname;
var fullurl = document.URL;
var xxx = fullurl.substring(fullurl.indexOf('#'));
var pageString = xxx.replace("#", "");
pageString = pageString.replace("http://www.mydomain.com/portfolio/photography.html", "");
if (pageString == "corporate") {
window.onload = function() {
var iframe = document.getElementById('U10511_animation');
var innerDoc = (iframe.contentDocument) ?
iframe.contentDocument : iframe.contentWindow.document;
var corporateRectangle = innerDoc.getElementById('Stage_Corporate_Rectangle');
corporateRectangle.click();
}
};
</script>
The above code will select the Corporate tab in the menu when viewed in Firefox but not IE when the URL has the suffix #corporate.
When I insert an 'alert' for the variable 'corporateRectangle' in Firefox it returns [HTMLObj] and in IE it returns 'null'.
Any ideas anyone? Thanks.
Have you tried checking the console for an error of some sort to help you and us understand the error?
IE JavaScript often works differently than in other browsers. And iframes are particularly problematical. One possibility is that you are getting the wrong document, such that the documentyou are retrieving either does not exist or does not contain the element you are looking for. So you just have to do some debugging. Here is how I would proceed. Run your script in IE.
1) Determine whether innerDoc is iframe.contentDocument or iframe.contentWindow.document. Make sure innerDoc is not null. If it is, try to get the document a different way.
2) Assuming innerDoc is not null, enumerate all of the elements in innerDoc. You can do that as follows:
for(i = 0; i < innerDoc.all.length; i++) alert(innerDoc.all [i].id);
Make sure that the id you are looking for is actually in the document. I suspect it isn't and that you need to get a different document object under IE.
I assume you are stuck with having to use iframes. If not, I suggest you use a different approach as iframes can be very problematical and browser-specific in how they work.
internet Explorer gets confused over name and id - it is highly recommended to treat these two attributes as if they were the same.
You can fix it either by 1) ensure that there are no id/name conflicts in your document, or 2)
override IE's native getElementById-method.
Read more about it here.
Ok... thanks to everyone who left suggestions.
The issue was that the menu animation has a preloader. Firefox ignores the preloader whereas IE treats the preloader as onLoad being complete. Therefore the attempt to access the element ID is null as it hasn't been loaded yet.
I decided to approach the problem from a different tack and read my bookmark from within the animation. This turned out to be a very simple solution once I figured out that I had to put the code in the first frame of the animation NOT in creationComplete or compositionReady.
This was the code: -
var bookmark = parent.window.location.hash;
bookmark = bookmark.replace("#", "");
if (bookmark == "corporate") {
sym.play("corp");
}
yes, as simple as that.

IE and firefox behave unpredictably updating location.hash on scroll()

I'm trying to update the location.hash by checking what div is currently active in a long scrolling site. This works fine is chrome, but is failing in Firefox and IE. I have tested with console.log and
I am able to see the id in console, but as soon as I try to feed this into the location hash the scrolling ceases to work on the page, or jumps around unpredictably!
$(window).scroll(function () {
$('div').each(function(){
if (
$(this).attr('class')=='article' && $(this).offset().top < window.pageYOffset + 10
&& $(this).offset().top + $(this).height() > window.pageYOffset + 10
) {
window.location.hash = $(this).attr('id')
}
});
});
First you need to understand that the scroll event fires many times a second. Combine that with the methodology you are using to search the DOM... look for every div, then filter all those div's for the ones you want and do this all many times a second...you are overloading the browser needlessly.
Scroll the window in this simple demo and see how often your script is firing; http://jsfiddle.net/tRx2P/
If you are going to search the DOM for the same elements repeatedly, caching them into variables will give a big performance boost. Searching the DOM is a lot more expensive than searching a cached variable containing elements
/* use jQuery selector that already filters out all the other `div` in page*/
var $articles= $('.article');
/* now use the variable inside your functions*/
$( window).scroll(function(){
$articles.each(.....
/* use the same cache principles for "$(this)" to help avoid needless function calls*/
})
Now the really important part is you should throttle back the number of times a second these need to be checked. There is no benefit in updating the hash multiple times while the user is still scrolling...and overloading the browser to do it
This modification of the demo only fires the code when user hasn't scrolled for 300ms which could likely be increased to 1/2 second or even more. It does this by constantly setting a timeout delay
http://jsfiddle.net/tRx2P/2/
You should be able to now adapt these concepts to the code you have

How to dynamically resize an iFrame (crossbrowser solution)

I am trying to include an iframe on a Drupal page. So far I successfully included the frame but the height resize function that I wrote only works in Internet Explorer. My goal is to make resize work inFirefox and Chrome as well. I searched the Internet but I couldn't find what I was looking for. Long story short, I want my frame to automatically resize height itself.
This is what I did so far (this is the code of the HTML page included in Drupal):
<script type="text/javascript">
function resize() {
var iframe = document.all.icw;
document.getElementById("icw").style.height = iframe.document.body.scrollHeight + "px";
}
</script>
<iframe id="icw" src="XXXXX" width="100%" scrolling="no" onload="resize()">
I understand that if the iframe lives on another domain the solution may be more difficult due to permissions. Is that correct?
These are the errors I get in Chrome and Firefox:
Chrome: Cannot read property 'body' of undefined
Chrome: JavaScript attempt to access frame with URL XXX from frame with URL YYY. Domains, protocols and ports must match.
Firefox: document.all is undefined
EDIT: What if I want to change one of the iframe element? In my case I need to change a textbox value. I understand I must do that when the page is loaded but I can't find a solution. No matter where I put the code I always a get a
Cannot call method 'getElementById' of undefined
when I try to access the iFrame textbox.
EDIT2: Asked a new question since they weren't related.
This solution works even cross-domain as long as you have access to both. There are a bunch of edge cases, but at least you can start with this. You can also add timer event to make sure iFrame is always a correct size so you never have scrollbar. Keep in mind this only works with browser supporting HTML5 due to the use of postMessage.
Inside iFrame
function resize(){
var body = document.body,
html = document.documentElement,
height = body.offsetHeight;
if(height === 0){
height = html.offsetHeight;
}
parent.postMessage({'action':'RESIZE', 'height':height}, '*');
}
Parent
function handleMessage(e) {
if (e.data.action == 'RESIZE') {
var targetHeight = e.data.height;
$('#iFrame').height(targetHeight);
}
}
window.addEventListener("message", handleMessage, false);
window.addEventListener("message", handleMessage, false);
This code do not work for IE.
For IE use
window.attachEvent("onmessage", handleMessage, false);
Check out this little library that does this and manages all the other edge cases for you.
https://github.com/davidjbradshaw/iframe-resizer

contentWindow.document.body is null

I have a problem in my javascript which is just to resize an iFrame based on the content. I have it working in other places but for this one example it is throwing an error. Using the following code the body is null and therefore can't get scrollHeight.
if(document.getElementById('iFrameHelpDesk') != null)
{
var Height = document.getElementById('iFrameHelpDesk').contentWindow.document.body.scrollHeight;
document.getElementById('iFrameHelpDesk').height = Height + 40;
}
The html used is:
<iframe src="http://<snipped webaddress>" id="iFrameHelpDesk" scrolling="no" frameborder="no"></iframe>
Why does this not populate the body object?
Fairly simply I took the code from the document load ($(function() {})) method and put it into it's own method for when the actual iframe loads. Ie.
$('#iFrameHelpDesk').load(function() {
var Height = document.getElementById('iFrameHelpDesk').contentWindow.document.body.scrollHeight;
document.getElementById(iFrameHelpDesk').height = Height + 40;
});
This works perfectly, as it should. But it's now confused me as to why some other iframes, which I perform similar code on, are working fine from within the document load. But this works and I'm happy enough with that.

Categories