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/
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.
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:
appendChild(node)
of existing node - thatnode
is first removed from the dom.Interesting thing here -
IE<=8
didn't reload the iframe - this behavior is (somewhat) new (sinceIE>=9
).According to Hallvord R. M. Steen comment, this is a quote from the iframe specs
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 fullremove
, even if the browsers uses thenode.removeChild
method).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!
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.
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 withflex-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.As you can see in the JS fiddle these
order
styles are inline to simplify theflip
button so rotate theiframes
.I sourced the solution from this StackOverflow question: Swap DIV position with CSS only
Hope that helps.