jQuery iframe load function not woking properly - javascript

I am using below code
<script type="text/javascript">
var counter = 0;
$('iframe').load(function() {
counter++;
alert("counter : "+counter);
alert("iframe len : "+$('iframe').length);
if (counter == $('iframe').length) {
doRedirect();
}
});
function doRedirect() {
alert("Inside doRedirect");
}
</script>
You can see I put some alert inside the above code.
First it gives me the alert counter : 1 and iframe len : 4 after that
alert counter : 2 and iframe len : 4 then it will proceed for other action they will not showing the alert counter : 3 and 4 as per the code and it is also not come to doRedirect function.
And in my console they gives me the below error
Load denied by X-Frame-Options: https://demo.testlab.local does not permit cross-origin framing.
So please help me what is wrong with this code.

Each time you run $('iframe'), a new query takes place.
You should cache the $('iframe') query, because the way you're doing it now is susceptible to just the sort of thing you're reporting. Starting here in your code, I'll explain...
$('iframe').load( ...
$('iframe') is a collection of <iframe> tags in the DOM when this line runs, and therefore you're attaching to all iframe tags in that collection, and only to those in that collection.
Later in the function body, you're comparing a static counter to the number of <iframe> tags in the DOM at a later time, via $('iframe').length. Calling $('iframe') creates a new collection based on the current state of the DOM, which could be different from the original collection.
So this is the most likely source of your trouble. Why? Because between the time you attached the load event handler and the time when this callback fires, anything in the DOM could have changed, including the number of iframe tags; e.g., if you have other scripts doing other things.
Suggested fix.
<script type="text/javascript">
var $iframes = $('iframe'),
counter = 0;
$iframes.load(function() {
counter++;
alert("counter : "+counter);
alert("iframe len : "+$iframes.length);
if (counter == $iframes.length) {
doRedirect();
}
});
function doRedirect() {
alert("Inside doRedirect");
}
</script>

Related

Sometimes, jQuery only updates elements on first page load

I'm learning javascript by creating a program which requests an API and dispays various properties (price in this example) to html. I have a few questions about my code and some problems I've been facing.
1). I have a bunch of $.getJSON functions corresponding to each value that I want to retrieve. I put them all in a a single 2 min. timer. When the page FIRST loads, however, some of the html elements fail to load at all. But if I refresh the page, they sometimes do load. If I refresh again, they might not load at all again. Every time I refresh, there's like a 10% chance of that particular function not inserting the content in the element. If it does load and I leave the page open, it will correctly function (update its value and html element every 2 mins and add/remove the green and red classes). If it doesn't load and I leave the page open, it will correctly function in 2 mins when the 2nd api request is made. I have already tested that the variables have some value (are not null) before and after each $('#price').text('$' + price);.
Here's an example of a function that does that:
var tempPrice;
var myVar = setInterval(myTimer, 1200000);
myTimer();
function myTimer() {
$.getJSON(link, function (json) {
$.each(json, function (index, value) {
if (value.id == "price") {
var price = value.price_eur;
if (!tempPrice) {
$('#price').text('$' + price);
tempPrice = parseFloat(price);
}
if (parseFloat(price) !== tempPrice) {
$('#price').text('$' + price).removeClass();
if (parseFloat(price) > tempPrice) {
setTimeout(function () {
$('#price').addClass("green");
}, 1);
} else {
setTimeout(function () {
$('#price').addClass("red");
}, 1);
}
tempPrice = parseFloat(price);
}
}
});
});
// Many more $.getJSON functions below...
}
If I run this function alone on either jsfiddle or my dev server (flask), it works fine. It only breaks down when I use it in conjunction with more api requests. If I remember correctly, I didn't have this problem before when I used to have a separate timer for each $.getJSON function and put each in its own <script> tag directly in html.
2) I know I can loop through the json instead of using $.each. How else can I improve the code?
1
As for the problem you're having with the inconsistent behavior of the initial page loading, it's because you are executing JavaScript before giving the browser the time to load the page fully first. You can solve this simply by waiting for the page the load, and then executing your code.
Example in jQuery:
$(document).ready(function() {
// Page is loaded, execute code...
});
2
To help you improve the way you're handling the supplied JSON data, a sample of the data would be useful.

Holy grail for determining whether or not local iframe has loaded

Firstly, I see this question asked a few times but no answers seem satisfactory. What I am looking for is to be able to call a script at anytime and determine whether or not an iframe has loaded - and to not limit the script to require being added to the iframe tag itself in an onload property.
Here's some background: I have been working on an unobtrusive script to try and determine whether or not local iframes in the dom have loaded, this is because one of our clients includes forms on their website in iframes and many of them open in lightboxes - which dynamically add the iframes into the dom at any time. I can attach to the open event of the lightbox, but its hit or miss as to whether I can "catch" the iframe before it has loaded.
Let me explain a little more.
In my testing I've determined that the onload event will only fire once - and only if it is bound before the iframe actually loads. For example: This page should only alert "added to iframe tag" and the listener that is attached afterward does not fire - to me that makes sense. (I'm using the iframe onload property for simple example).
https://jsfiddle.net/g1bkd3u1/2/
<script>
function loaded () {
alert ("added to iframe tag");
$("#test").load(function(){
alert("added after load finished");
});
};
</script>
<iframe onload="loaded()" id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
My next approach was to check the document ready state of the iframe which seems to work in almost all of my testing except chrome which reports "complete" - I was expecting "Access Denied" for cross domain request. I'm ok with a cross domain error because I can disregard the iframe since I am only interested in local iframes - firefox reports "unintialized" which I'm ok with because I know I can then attach an onload event.
Please open in Chrome:
https://jsfiddle.net/g1bkd3u1/
<iframe id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
<script>
alert($("#test").contents()[0].readyState);
</script>
I've found that if I wait just 100ms - then the iframe seems to report as expected (a cross domain security exception - which is what I want - but I don't want to have to wait an arbitrary length).
https://jsfiddle.net/g1bkd3u1/4/
<iframe id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
<script>
setTimeout(function () {
try {
alert($("#test").contents()[0].readyState);
} catch (ignore) {
alert("cross domain request");
}
}, 100);
</script>
My current workaround / solution is to add the onload event handler, then detach the iframe from the dom, then insert it back into the dom in the same place - now the onload event will trigger. Here's an example that waits 3 seconds (hoping thats enough time for the iframe to load) to show that detaching and re-attaching causes the iframe onload event to fire.
https://jsfiddle.net/g1bkd3u1/5/
<iframe id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
<script>
setTimeout(function(){
var placeholder = $("<span>");
$("#test").load(function(){
alert("I know the frame has loaded now");
}).after(placeholder).detach().insertAfter(placeholder);
placeholder.detach();
}, 3000);
</script>
While this works it leaves me wondering if there are better more elegant techniques for checking iframe load (unobtrusively)?
Thank you for your time.
Today I actually ran into a bug where my removing and re-inserting of iframes was breaking a wysiwyg editor on a website. So I created the start of a small jQuery plugin to check for iframe readiness. It is not production ready and I have not tested it much, but it should provide a nicer alternative to detaching and re-attaching an iframe - it does use polling if it needs to, but should remove the setInterval when the iframe is ready.
It can be used like:
$("iframe").iready(function() { ... });
https://jsfiddle.net/q0smjkh5/10/
<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>
The example waits until the window has loaded to dynamically add an iframe to the DOM, it then alerts its document's readyState - which in chrome displays "complete", incorrectly. The iready function should be called after and an attempt to output the document's readyState proves cross domain exception - again this has not been thoroughly tested but works for what I need.
I encountered a similar issue in that I had an iframe and needed to modify its' document once it had finished loading.
IF you know or can control the content of the loaded document in the iFrame, then you could simply check for/add an element that you could check the existence of in order to then update the iframe document.
At least then you know the elements you want to work with are loaded in to the document.
In my case, I called a function, which itself checked for the existence of my known element that would always be found after the elements I needed to update had already been loaded - in the case it was not found, it called itself again through setTimeout().
function updateIframeContents() {
if ($("#theIframe").contents().find('.SaveButton').length > 0) {
// iframe DOM Manipulation
} else {
setTimeout(updateIframeContents, 250);
}
}
updateIframeContents();

jQuery not loading javascripts

So I'm stuck behind this problem
I'm using AJAX to refresh my website and when I also need to add scripts to my newly loaded div. Foe this I'm using this piece of code
$.getScript('scripts/shBrushJava.js');
$.getScript('scripts/shCore.js');
setTimeout(function(){
$(".left-content").load(document.location.hash.substr(1));
}, 10);
Sometimes this works and sometimes not as shown on pictures below
This is the working 2 pictures (Website and Firebug console)
These are the images from the time it's not working (95%)
As you can see, when the JS is not loaded properly, they are shown in console. How to fix this?
As mentioned, ajax is asynchronous. So you are not guaranteed that the script files is loaded at any given time. You've set a timeout for 10 milliseconds. Some times, the files may have been loaded and parsed, sometimes not.
Here is an example on how you can guarantee that the scripts are loaded, but there is a tons of third party libraries available for this already. For example RequireJS.
Simple example:
var getAllScripts = function (scripts, callback) {
var i, count = scripts.length;
// Start loading all files
for (i = 0; i < scripts.length; i += 1) {
$.getScript(scripts[i], function () {
// When loaded, decrease count
count -= 1;
// If all is loaded, call the callbacl
if (count === 0) {
callback();
}
});
};
};
getAllScripts([
'scripts/shBrushJava.js',
'scripts/shCore.js'
],
function () {
// Here all files is loaded, do your magic here
alert('All is loaded');
}
);
Here is a fiddle to try it out
Or you can just put:
<script src="scripts/shCore.js" type="text/javascript"></script>
<script src="scripts/shBrushJava.js" type="text/javascript"></script>
In your <head> in your html. Then it's guaranteed to be loaded in the whole <body>.

window.location.reload complete?

I call
window.location.reload(false)
in a javascript method to update the page. I have additional javascript calls after this call. Is there a way to know when window.location.reload(false) has completed running before calling the additional javascript calls?
You simply have to provide a function to onload : a reload isn't different from a load.
window.onload = function() { // ...
Your line of code window.location.reload(false) causes the browser to reload the current page - no script after this statement will be executed ....
You could set a cookie on first load - then on subsequent loads check for the existence of the cookie and perform an action ... pseudo code :
onload = check cookie
if cookie is present
run function
else
set cookie
reload
You could check the time on the cookie and choose to execute the function after a period of time (1 hour for example) has passed ....
I use the hashtag to set variables that tells me if the page is reloaded or not. You could do something like this:
// Get the hash of the page
var hashstring = window.location.hash.substring(1);
var found = false;
// Do a hash exist?
if (hashstring.length > 0)
{
// Split the hash by '&'-sign (in case you have more variables in the hash, as I have)
var a = hashstring.split("&");
// Loop through the values
for (i = 0; i < a.length; i++)
{
// Split the string by '=' (key=value format)
var b = a[i].split("=");
// If the key is 'reloaded' (which tells us if the page is reloaded)
if(b[0] == 'reloaded')
{
found = true;
}
}
}
if(!found)
{
location.hash = 'reloaded=true';
window.location.reload();
}
// Do other stuff, this will only be executed if the page has been reloaded
I've put the code that finds a variable in the hash in a seperate function in my project, but fot simplicity I just added it here above. This makes it possible to determine if the page has been reloaded, and run code only if it has.

How to make my function to be page specific or div id specific?

I am writing javascript to my web pages, but there is a number of functions and loops, that i think are running in all pages, so the first one is running and failing on the second page. Because of this, the javascript function on the second page is not running.
Can anyone give me an idea of how to create page-specific functions or check the availability of an id? I don't use any frameworks.
thanks in advance.
my javascript code is :
window.onload = function(){
var yellows = document.getElementById('magazine-brief').getElementsByTagName('h2');
var signUp = document.getElementById('signup-link');
function animeYellowBar(num){
setTimeout(function(){
yellows[num].style.left = "0";
if(num == yellows.length-1){
setTimeout(function(){
signUp.style.webkitTransform = "scale(1)";
},num * 250);
}
}, num * 500);
}
for (var i = 0; i < yellows.length; i++){
animeYellowBar(i);
}
alert("alert second page");
}
in this code, the alert message not working on second page. any idea?
If I understand you correctly, you have a javascript function, that you want to attach to an event from a specific div element in your page.
a) Include an event directly to you HTML page, something like this:
<div id="element" onclick="some_function();">Text is here</div>
b) Use a javascript function (add this code between <script> tag):
window.onload = function() {
document.getElementById("element").setAttribute("onclick", "some_function()")
}
The best way would be to only include those scripts on the pages which need them. Why waste time loading and parsing scripts you don't need?
If you must keep them on every page, put your functions in an if statement and check for something unique to the page that needs them (such as a form element or field ID).
Update
In response to your comment:
You have to code more defensively. You are attempting to make use of the magazine-brief and signup-link elements before you have made certain that they exist. Never trust that the proper element was returned - always check that it was before attempting to use that element.
I suggest checking your vars like so:
var yellows = document.getElementById('magazine-brief').getElementsByTagName('h2');
var signUp = document.getElementById('signup-link');
if (yellows != 'undefined' && signUp != undefined)
{
function animeYellowBar(num)
{
//...
}
}

Categories