I have an array of two urls that I read and feed into an iframe src value using:
document.getElementById("iframe").src = unescape(dashboard.url);
Immediately after this line, I issue an alert(document.getElementById("iframe").src), which all works fine.
My problem is, is that the first URL in the array seems to load correctly and the alert display the correct URL being used by the iframe.
But when the second URL comes around to be processed and fed into the iframe src value, the alert displays the correct URL, but my iframe which is on the same page is not being refreshed with the correct URL and so still displays the first URL in my array that worked previously.
Am I missing something - is this an IE6 bug of some sort as from what I can see, the iframe second time around is not being called.
I noticed this by putting an onLoad="alert('Test');" in my iframe and it only appeared once and NOT the second time for the second URL.
Any ideas?
By the way, I am using a setTimeout() call to cycle through the arrays.
Thanks.
See it in action. (works x-browser)
<iframe id="rotator" src="http://...first"></iframe>
<script>
// start when the page is loaded
window.onload = function() {
var urls = [
"http://...first",
"http://...second",
// ....
"http://...tenth" // no ,!!
];
var index = 1;
var el = document.getElementById("rotator");
setTimeout(function rotate() {
if ( index === urls.length ) {
index = 0;
}
el.src = urls[index];
index = index + 1;
// continue rotating iframes
setTimeout(rotate, 5000);
}, 5000); // 5000ms = 5s
};
</script>
Related
I want to refresh the whole page when javascript detects a change in json data.
Here is the code i am trying:
var previous = null;
var current = null;
setInterval(function(){
$.getJSON("https://www.mylivepolls.com/json.php?shortURL=0", function(json){
current = JSON.stringify(json);
if(previous && current && previous !== current){
console.log('refresh');
location.reload();
}
previous = current;
});
}, 1000);
When this code is executed, it does not refresh the page.
But when i try to open inspect element on that page, it refreshes!
please check if i am doing something wrong.
Possibly when your debugger has focus, 'location' is being scoped to the frame of the debugger. Try window.location.reload(), instead of simply location.reload().
I have an iframe that's supposed to load different modules of a web application.
When the user clicks a navigation menu in the top window, it's passes a new url to the iframe. The trouble is, the new url doesn't actually point to a new page, it only uses a changed hash.
i.e.:
User clicks "dashboard", iframe src set to application.html#/dashboard
User clicks "history", iframe src set to application.html#/history
This means that the iframe does not actually load the src url again because hash changes don't require it to. The application inside the iframe is an angular app which loads the required modules dynamically using requireJS. We need this functionality to remain.
I need to force the frame source to load again even though only the hash changed. It's possible that I instead find a way to rewrite our angular app to dynamically unload/load the modules on push state events but that introduces several layers of issues for the app, plus some IE trouble.
I've tried:
Setting iframe src and calling it's location.reload, but that reloads the originally loaded url
Setting the iframe location.href/hash and calling reload, same issue
Blanking the src attribute and then setting the new url - no effect
The only solution I can find is to set the src to a blank screen, then onload set it to the new url:
var appIFrame = document.getElementById('appIFrame');
appIFrame.src = 'about:blank';
appIFrame.onload = function(){
appIFrame.src = '// set the real source here';
appIFrame.onload = false;
}
This works, yet it seems inefficient because there's an extra step.
Maybe add a dynamic GET parameter – f.e. the current timestamp, which you can get from the JavaScript Date object – to the iframe URL.
Instead of assigning application.html#/dashboard as src value, assign application.html?1234567890#/dashboard from your outside page (with 1234567890 replaced by the current timestamp, obviously).
I don't have a specific answer for you. However, the following script may proved useful (I wrote this about a year or so ago). The following script deals with re-adjusting iframe height when the document changes. This script was tested cross-browser. It does deal with the issues you're experience but indirectly. There is a lot of commenting with the Gist:
https://gist.github.com/say2joe/4694780
Here my solution (based on this stackoverflow answer):
var $ = function(id) { return document.getElementById(id); };
var hashChangeDetector = function(frame, callback) {
var frameWindow = frame.contentWindow || frame.contentDocument;
// 'old' browser
if (! "onhashchange" in window) {
var detecter = function(callback) {
var previousHash = frameWindow.location.hash;
window.setTimeout(function() {
if (frameWindow.location.hash != previousHash) {
previousHash = frameWindow.location.hash;
callback(previousHash);
}
}, 100);
};
}
else // modern browser ?
{
var detecter = function(callback) {
frameWindow.onhashchange = function () {
callback(frameWindow.location.hash);
}
};
}
detecter(callback);
};
hashChangeDetector($('myframe'), function(hash) {
alert ('detecting hash change: ' + hash);
});
You can test this here: http://paulrad.com/stackoverflow/iframe-hash-detection.html
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.
hi this all started when i ran a function (lets call it loadround) that altered the innerHTML of an iframe. now once loadframe was loaded there were links in the iframe that once clicked would change the iframe page. the only problem is when i click the back button the loadround page was gone. i've thought about this numerous times to no avail. so i tried this code.
loadround
then
function loadround(a,b){
window.location.hash = "#loadround('"+a+"','"+b+"')";
var code = "<(h2)>"+a+"</(h2)><(h2)>"+b+"</(h2)>"
var iFrame = document.getElementById('iframe');
var iFrameBody;
iFrameBody = iFrame.contentDocument.getElementsByTagName('body')[0]
iFrameBody.innerHTML = code;
}
(the brackets in the h2 are intentional)
then i would try to reload the function by possibly an onload function but for now i was testing with a simple href as followed.
function check(){
var func = location.hash.replace(/#/, '')
void(func);
}
check
unfortunately the check code doesn't work and im almost certain there is an easier way of doing this. i tried changing the src of the iframe instead of the innerhtml and there was the same problem. thanks in advance
The modern browsers are starting to support the event window.onhashchange
In the meantime you can use the workaround proposed by Lekensteyn or maybe you can find something useful here: JavaScript/jQuery - onhashchange event workaround
You are misunderstanding the function void, which just make sure the return value is undefined. That prevents the browser from navigating away when you put it in a link. You can test that yourself by pasting the next addresses in your browser:
javascript:1 // note: return value 1, browser will print "1" on screen
javascript:void(1) // note: undefined return value, browser won't navigate away
It's strongly discouraged to execute the hash part as Javascript, as it's vulnerable to XSS without proper validating it. You should watch the hash part, and on modification, do something.
An example; watch every 50 milliseconds for modifications in the hash part, and insert in a element with ID targetElement an heading with the hash part. If the hash part is not valid, replace the current entry with home.
var oldHash = '';
function watchHash(){
// strip the first character (#) from location.hash
var newHash = location.hash.substr(1);
if (oldHash != newHash) {
// assume that the parameter are alphanumeric characters or digits
var validated = newHash.match(/^(\w+)$/);
// make sure the hash is valid
if (validated) {
// usually, you would do a HTTP request and use the parameter
var code = "<h1>" + validated[1] + "</h1>";
var element = document.getElementById("targetElement");
element.innerHTML = code;
} else {
// invalid hash, redirect to #home, without creating a new history entry
location.replace("#home");
}
// and set the new state
oldHash = newHash;
}
}
// periodically (every 50 ms) watch for modification in the hash part
setInterval(watchHash, 50);
HTML code:
Home
About Me
Contact
<div id="targetElement">
<!-- HTML will be inserted here -->
</div>
I'm using the following code to insert some HTML into a div, and to preload any images that might be contained in that HTML (the html var's data is actually fetched from an AJAX request in the real code). This is to prevent the browser from loading the fetched HTML's images upon showing the div (using the slideDown event) - because this results in the effect's fluidity being broken as it loads image mid-transition. I suppose I could use an interlaced JPEG so that the dimensions of the image are known almost immediately, but obviously it'd be nice to get a cleaner method worked out. :P
var html = '<img src="images/test.jpg" alt="test" />';
$('div.content').hide().html(html);
$('div.content img').each(function(){
var img = new Image();
img.src = $(this).attr('src');
$(this).attr('src', img.src);
});
$('div.content').slideDown('normal');
I'm using the Image object and its subsequent assigning as per the advice given here, but unfortunately the image still isn't cached by the browser using this method, because the sildeDown() effect is still interrupted as the image loads.
Any help or alternative methods? Many thanks.
Edit - 21st Sept 09
Progress! Turns out the browser was caching the image, I just wasn't giving it time to do so (it just needed a second to load with an alert() or setInterval()). Now introducing what is probably the messiest code ever - I am using an infinite loop to create that pause.
The new method extends the old code above by binding a function (that adds each image's src to an array) to that image's successful load event. It then gets stuck in an infinite loop as it waits until all the images have loaded and therefore appeared in the array. This seems to work as a way to synchronously pre-load images - but a problem remains; the while() loop for some reason cycles infinitely even once all the images are loaded, unless I add an alert() to pause it for a moment.
The new code:
var html = '<img src="images/test.jpg" alt="test" />';
$('div.content').hide().html(html);
// define usr variables object
$.usrvar = {};
// array of loaded images' urls
$.usrvar.images = [];
// boolean for whether this content has images (and if we should check they are all loaded later)
$.usrvar.hasimages = false;
// foreach of any images inside the content
$('div.content img').each(function(){
// if we're here then this content has images..
$.usrvar.hasimages = true;
// set this image's src to a var
var src = $(this).attr('src');
// add this image to our images array once it has finished loading
$(this).load(function(){
$.usrvar.images.push(src);
});
// create a new image
var img = new Image();
// set our new image's src
img.src = src;
});
// avoid this code if we don't have images in the content
if ($.usrvar.hasimages != false) {
// no images are yet loaded
$.usrvar.imagesloaded = false;
// repeatedly cycle (while() loop) through all images in content (each() loop)
while ($.usrvar.imagesloaded != true) {
$('div.content img').each(function(){
// get this loop's image src
var src = $(this).attr('src');
// if this src is in our images array, it must have finished loading
if ($.usrvar.images.indexOf(src) != -1) {
// set imagesloaded to trueai
$.usrvar.imagesloaded = true;
} else {
// without the pause caused by this alert(), this loop becomes infinite?!
alert('pause');
// this image is not yet loaded, so set var to false to initiate another loop
// (ignores whether imagesloaded has been set to true by another image, because ALL
// need to be loaded
$.usrvar.imagesloaded = false;
}
});
}
}
$('div.content').slideDown('normal');
I made the following solution but it hasn't been tested, so you're warned ;)
// HTML (any formatting possible)
// no src for the images: it is provided in alt which is of the form url::actualAlt
var html = "<p><img alt='images/test.jpg::test' /><br />Some Text<br /><img alt='images/test2.jpg::test2' /></p>";
$(document).ready(function() {
// Reference to the content div (faster)
var divContent = $("div.content");
// Hide the div, put the HTML
divContent.hide().html(html);
// Webkit browsers sometimes do not parse immediately
// The setTimeout(function,1) gives them time to do so
setTimeout(function() {
// Get the images
var images = $("img",divContent);
// Find the number of images for synchronization purpose
var counter = images.length;
// Synchronizer
// will show the div when all images have been loaded
function imageLoaded() {
if (--counter<=0) $('div.content').slideDown('normal');
}
// Loading loop
// For each image in divContent
$.each(images,function() {
// Get the url & alt info from the alt attribute
var tmp = $(this).attr("alt").split("::");
// Set the alt attribute to its actual value
$(this).attr("alt",tmp[1]);
// Wire the onload & onerror handlers
this.onload = this.onerror = imageLoaded;
// Set the image src
this.src = tmp[0];
});
},1);
});
Create an interval/timeout and let it check your compterGenerated css-height, if it's autosized it'll begin from 0 and end to 100 (for example). But in Safari it loads the height before the image, so it'll propably not work in all browsers...
I was playing with this and I created a slightly different solution. Instead of pushing images onto an array when they are loaded, you push them all onto an array in the loop, then in the load event you remove them from the array and call a 'finished' function. It checks if the images array is empty, and if it is then it clears up and shows the content.
var html = '< animg src="images/test.jpg" alt="test" />'; // not allowed to post images...
$('div.content').hide().html(html);
// preload images
// define usr variables object
$.usrvar = {};
// array of loaded images' urls
$.usrvar.images = [];
// initially no images
$.usrvar.hasimages = false;
$('div.content img').each(function() {
// if we're here then this content has images..
$.usrvar.hasimages = true;
// set this image's src to a var
var src = this.src;
// add this image to our images array
$.usrvar.images.push(src);
// callback when image has finished loading
$(this).load(function(){
var index = $.usrvar.images.indexOf(src);
$.usrvar.images.splice(index,1);
finish_loading();
});
// create a new image
var img = new Image();
// set our new image's src
img.src = src;
});
if(!$.usrvar.hasimages) finish_loading();
function finish_loading() {
if($.usrvar.hasimages) {
if($.usrvar.images.length > 0) return;
}
$('div.content').slideDown('normal');
}
Edit: Looking at Julien's post, his method is better. My method works in a similar way but like the original solution keeps track of images by an array of srcs rather than just a count (which is more efficient).
Edit 2: well I thought it was a better solution, but it seems it doesnt work for me. Maybe something to do with the load event getting called too close to each other. Sometimes it will work but sometimes it will hang when loading images, and the image counter never reaches zero. I've gone back to the method in my post above.
Edit 3: It appears it was the setTimeout that was causing the problem.
This is what I use. As you can see by my points, I'm no pro, but I found this somewhere and it works great for me and seems much simpler than everything posted. Maybe I missed a requirement though. :)
var myImgs = ['images/nav/img1.png', 'images/nav/img2.png', 'images/nav/img3.png', 'images/nav/img4.png', 'images/expand.png', 'images/collapse.png'];
function preload(imgs) {
var img;
for (var i = 0, len = imgs.length; i < len; ++i) {
img = new Image();
img.src = imgs[i];
}
}
preload(myImgs);