Take a look at this simple HTML:
<div id="wrap1">
<iframe id="iframe1"></iframe>
</div>
<div id="warp2">
<iframe id="iframe2"></iframe>
</div>
Let's say I wanted to move the wraps so that the #wrap2 would be before the #wrap1. The iframes are polluted by JavaScript. I am aware of jQuery's .insertAfter() and .insertBefore(). However, when I use those, the iFrame loses all of its HTML, and JavaScript variables and events.
Lets say the following was the iFrame's HTML:
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
// The variable below would change on click
// This represents changes on variables after the code is loaded
// These changes should remain after the iFrame is moved
variableThatChanges = false;
$(function(){
$("body").click(function(){
variableThatChanges = true;
});
});
</script>
</head>
<body>
<div id='anything'>Illustrative Example</div>
</body>
</html>
In the above code, the variable variableThatChanges would...change if the user clicked on the body. This variable, and the click event, should remain after the iFrame is moved (along with any other variables/events that have been started)
My question is the following: with JavaScript (with or without jQuery), how can I move the wrap nodes in the DOM (and their iframe childs) so that the iFrame's window stays the same, and the iFrame's events/variables/etc stay the same?
It isn't possible to move an iframe from one place in the dom to another without it reloading.
Here is an example to show that even using native JavaScript the iFrames still reload:
http://jsfiddle.net/pZ23B/
var wrap1 = document.getElementById('wrap1');
var wrap2 = document.getElementById('wrap2');
setTimeout(function(){
document.getElementsByTagName('body')[0].appendChild(wrap1);
},10000);
This answer is related to the bounty by #djechlin
A lot of search on the w3/dom specs and didn't find anything final that specifically says that iframe should be reloaded while moving in the DOM tree, however I did find lots of references and comments in the webkit's trac/bugzilla/microsoft regarding different behavior changes over the years.
I hope someone will find anything specific regarding this issue, but for now here are my findings:
According to Ryosuke Niwa - "That's the expected behavior".
There was a "magic iframe" (webkit, 2010), but it was removed in 2012.
According to MS - "iframe resources are freed when removed from the DOM". When you appendChild(node) of existing node - that node is first removed from the dom.
Interesting thing here - IE<=8 didn't reload the iframe - this behavior is (somewhat) new (since IE>=9).
According to Hallvord R. M. Steen comment, this is a quote from the iframe specs
When an iframe element is inserted into a document that has a browsing context, the user agent must create a new browsing context, set the element's nested browsing context to the newly-created browsing context, and then process the iframe attributes for the "first time".
This is the most close thing I found in the specs, however it's still require some interpretation (since when we move the iframe element in the DOM we don't really do a full remove, even if the browsers uses the node.removeChild method).
Whenever an iframe is appended and has a src attribute applied it fires a load action similarly to when creating an Image tag via JS. So when you remove and then append them they are completely new entities and they refresh. Its kind of how window.location = window.location will reload a page.
The only way I know to reposition iframes is via CSS. Here is an example I put together showing one way to handle this with flex-box:
https://jsfiddle.net/3g73sz3k/15/
The basic idea is to create a flex-box wrapper and then define an specific order for the iframes using the order attribute on each iframe wrapper.
<style>
.container{
display: flex;
flex-direction: column;
}
</style>
<div class="container">
<div id="wrap1" style="order: 0" class="iframe-wrapper">
<iframe id="iframe1" src="https://google.com"></iframe>
</div>
<div id="warp2" style="order: 1" class="iframe-wrapper">
<iframe id="iframe2" src="https://bing.com"></iframe>
</div>
</div>
As you can see in the JS fiddle these order styles are inline to simplify the flip button so rotate the iframes.
I sourced the solution from this StackOverflow question: Swap DIV position with CSS only
Hope that helps.
If you have created the iFrame on the page and simply need to move it's position later try this approach:
Append the iFrame to the body and use a high z-index and top,left,width,height to put the iFrame where you want.
Even CSS zoom works on the body without reloading which is awesome!
I maintain two states for my "widget" and it is either injected in place in the DOM or to the body using this method.
This is useful when other content or libraries will squish or squash your iFrame.
BOOM!
Unfortunately, the parentNode property of an HTML DOM element is read-only. You can adjust the positions of the iframes, of course, but you can't change their location in the DOM and preserve their states.
See this jsfiddle I created that provides a good test bed. http://jsfiddle.net/RpHTj/1/
Click on the box to toggle the value. Click on the "move" to run the javascript.
This question is pretty old... but I did find a way to move an iframe without it reloading. CSS only. I have multiple iframes with camera streams, I dont like when they reload when i swap them. So i used a combination of float, position:absolute, and some dummy blocks to move them around without reloading them and having the desired layout on demand (resizing and all).
If you are using the iframe to access pages you control, you could create some javascript to allow your parent to communicate with the iframe via postMessage
From there, you could build login inside the iframe to record state changes, and before moving dom, request that as a json object.
Once moved, the iframe will reload, you can pass the state data into the iframe and the iframe listening can parse the data back into the previous state.
PaulSCoder has the right solution. Never manipulate the DOM for this purpose. The classic approach for this is to have a relative position and "flip" the positions in the click event. It's only not wise to put the click event on the body, because it bubbles from other elements too.
$("body").click(function () {
var frame1Height = $(frame1).outerHeight(true);
var frame2Height = $(frame2).outerHeight(true);
var pos = $(frame1).css("top");
if (pos === "0px") {
$(frame1).css("top", frame2Height);
$(frame2).css("top", -frame1Height);
} else {
$(frame1).css("top", 0);
$(frame2).css("top", 0);
}
});
If you only have content that is not cross-domain you could save and restore the HTML:
var htmlContent = $(frame).contents().find("html").children();
// do something
$(frame).contents().find("html").html(htmlContent);
The advantage of the first method is, that the frame keeps on doing what it was doing. With the second method, the frame gets reloaded and starts it's code again.
At least in some circumstances a shadow dom with slotting might be an option.
<template>
<style>div {outline:1px solid black; height:45px}</style>
<div><slot name="a" /></div>
<div><slot name="b" /></div>
</template>
<div id="shadowhost">
<iframe src="data:text/html,<button onclick='this.innerText+=`!`'>!</button>"
slot="a" height=40px ></iframe>
</div>
<button onclick="ifr.slot= (ifr.slot=='a') ? 'b' : 'a';">swap</button>
<script>
document.querySelector('#shadowhost').attachShadow({mode: 'open'}).appendChild(
document.querySelector('template').content
);
ifr=document.querySelector('iframe');
</script>
In response to the bounty #djechlin placed on this question, I have forked the jsfiddle posted by #matt-h and have come to the conclusion that this is still not possible.
http://jsfiddle.net/gr3wo9u6/
//this does not work, the frames reload when appended back to the DOM
function swapFrames() {
var w1 = document.getElementById('wrap1');
var w2 = document.getElementById('wrap2');
var f1 = w1.querySelector('iframe');
var f2 = w2.querySelector('iframe');
w1.removeChild(f1);
w2.removeChild(f2);
w1.appendChild(f2);
w2.appendChild(f1);
//f1.parentNode = w2;
//f2.parentNode = w1;
//alert(f1.parentNode.id);
}
I have this little issue here with my page, where if I reload it while being anchored, the anchor remains and there is a problem to it. I.E
http://localhost/public/product/1#mod1
The anchor is #mod1, and while the anchor remains active after refresh, my CSS code is saying that this element:
.overlay:target
is active. Which is a very big issue, because then it doesn't allow me to explore the functionallity I have implemented on this anchor, unless I remove the #mod1 from the end of the page manually by hand. Because this CSS element makes this div visible when it should be not unless activated with the a href element.
(?)
<div id="mod{{$key}}" class="overlay">
content
</div>
Any ideas on how could I solve it? I tried catching whether the user has refreshed the page and redirecting him to an action/route/url, but the page stays blank then and URL unchanged.
You cannot use href with angularJS because it will misdirect the target link. AngularJS is a markup language for HTML, it is not HTML. Because angularJS is not HTML, we're provided a special set of directives to write angularJS values inline into HTML markup. The answer to solve your issue would be to replace the href tag in the anchor element with the angularJS directive ngHref. You can find more information about how to use ngHref and other directives at the link below. Good luck.
https://docs.angularjs.org/api/ng/directive/ngHref
Well I wanted to purely solve this without JS, but here's what I did, HTML:
<a ng-href="mod{{$key}}" class="button">(?)</a>
<div id="mod{{$key}}" class="overlay">
Then replaced the CSS of overlay:target to -> overlay:active, and implemented JS:
var curmod;
$('a.button').on('click', function(e)
{
curmod = document.getElementById($(this).attr('ng-href'));
$(curmod).addClass('active');
});
$('.popup a.close').on('click', function(e)
{
$(curmod).removeClass('active');
curmod = null;
});
I'm attempting to change an IFrame twice with the click of one link. I continuously get this error: Uncaught TypeError: Cannot set property 'src' of null whenever that link is clicked.
What this needs to do, is change the source of the IFrame on the index page, and then change the source of an IFrame on the page that was loaded into the outer IFrame on the index page.
<div class="subjects list-group" target="../../body.html ">
<script>
function doneLoading() {
document.getElementById('index.html#large-column').src = 'body.html';
}
</script>
<span class="badge">26</span>English
</div>
A cleaner approach would be to use iframe targeting.
<iframe id='content' src='body-default.html'>
<a href='body-en.html' target='content'>English</a>
The body-default.html or body-en.html files could contain javascript to update themselves if needed.
Another way you can look at the problem - is to take the opposite approach - and create a series of pages - and load them in the standard way. You could use iframes to remove duplicated content e.g. headers and footers if needed.
It is hard to assist further without understanding your use case in more detail.
There is a simple HTML page, named say abc.html. Now abc.html has a button named say 'click me'. This page, abc.html, also has an iframe, with an id say 'myframe'.
Now what i want is that when the button, 'click me', is clicked an alert box should come up inside the iframe named 'myframe'. How can i do this?
I have tried the following..
window.frames[0].contentWindow.alert("this is the iframe");
but this does not seem to work. Please let me knwo why does this not work and what could be an alternate solution.
ContentWindow is derived from document, not window.
What you will want to do is add the alert into a function on the iframe page, then use document.getElementById('targetFrame').contentWindow.targetFunction(); to call it, (using targetFunction as example). This answer may give you further information on techniques.
If the source of the <iframe> comes from a different domain than the parent page, the you are going to hit browsers same origin policy, meaning that you simply cannot do anything with that page.
For an "alternative suggestion" it really does depend on exactly what you are trying to achieve, and what the user is supposed to experience.
Browser-level alert is not visibly tied to a particular frame. You will always get an alert that is centered on the browser window, rather than centered on the window/frame it is called from.
JSFiddle demonstrating this
If you need this functionality, you'll have to use your own modal dialogues, or a library that will present them.
This might helpful to you:
function body_load()
{
document.getElementById('loader').src;
}
<div id='mydiv'>
<input type="button" value="Click Me" onclick="body_load();" />
</div>
<iframe id='loader' onload="body_load(this)" name="Google" scrolling="auto" style="width:95%;height:600px" src="http://www.image.com"></iframe>
http://jsbin.com/idazul/1/edit
I have a scenario where a javascript function creates a new span element in web page present in main window of browser--
Code for this is given below--
document.createElement('span');
Now I want to extend this code to make it work in an iframe as well... I have figured out that for this to happen, the above code should be modified so that the span element is created within the iframe. I have with me the id/name of the iframe in which the span element has to be created... How do I create the span element in iframe?
I understand that the web page in iframe should belong to same domain as page contained in main window(viz Same Origin Policy)...
if i get u right u need to add an element in a page in iframe
use this code
var ifrm= document.getElementById('iframe id');
var ifrmdocument = ifrm.contentWindow.document;
var spn=ifrmdocument.createElement('span');
spn.innerHTML='Hello';
ifrmdocument.appendChild(spn);
Regards
Any Questions iam here
if my answer is useful please mark it as correct one