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);
}
Unfortunately I cannot post a working code/example because it's part of a huge HTML template and I cannot extract only the interesting part :( sorry for that.
Anyway, I have this popup that I define like this:
<a id='bookShopping' class="popup-text" href="#book-shopping-dialog"></a>
<div id="book-shopping-dialog" class="mfp-dialog mfp-hide">
random popup text...
<button>Close the popup!!!</button>
</div>
and that I call with
<a onclick="document.getElementById('bookShopping').click(); return false;" >PopUp!</a>
The popup itself has a "X" close button on the upper right corner, defined with
<button class="mfp-close">X</button>
I want MY BUTTON, inside the "random text", to be able to close the popup as well.
I tried:
1) Give my button the mfp-close class.
NOPE. My button will jump to the upper right corner
2) Setting the div to display:none and/or display:block
NOPE. The popup will close but IT WILL NEVER REAPPEAR.
So, my last resort would be to call the same code that the "mfp-close" class is calling. My problem is that I can only find the mfp-close class defined in CSS, nothing in JS.
If I try to "inspect" the "X" button, it will not give me any event linked to it, nor any JS associated with its "click".
I know that without the source code is hard to understand, but the general question is: where, in Chrome or Firefox, can I find ALL THE JS CODE EXECUTED when I click on an element?
Thank you in advance.
You appear to be using the Magnific popup jQuery plugin, which has an API including a close() method. You should call that method rather than try to hack around with classes.
http://dimsemenov.com/plugins/magnific-popup/documentation.html
$.magnificPopup.close();
I have a problem with a very simple JavaScript pop-up script.
I have this example page: http://www.onofri.org/example/example4/
At the end of this page there is a box containing some flags including the British flag that is reprsented by the #reportEng div (inside the engLink link).
What I want is that when the user clicks on this element a pop0up message will show.
So I have add to the page this simple script:
<script>
var test = document.getElementById('engLink');
test.addEventListener('click', function() {
alert('clicked');
});
</script>
I have put the script inside the body section of the page and not in the head section because this is only a test page and the final result will be put into a page of a CMS in which I do not have access to the template (so I can't put the script in the head section).
The problem is that it does not work. If I click on the English flag the page is reloaded and the pop-up not shown.
Can you help me?
Thank you,
Andrea
I went a completely different approach. The addEventListener is pretty cool, but I'm a bit OLD and I've defaulted to nasty habits. This works just fine for me.
<script>
function myExample(){
alert("BaZing! It works!");
}
</script>
And for the HTML part...
<div id="reportEng" onClick="myExample()"></div>
I also want to point out that this 'fix' is a bit taboo (see here)
You don't prevent the link from being followed, so when you click the link which has an empty href, you simply reload the current page.
There are many ways to prevent the defaul link behaviour, but here is the old school way:
<div id="reportEng"></div>
Also on a side note I don't think a div element is allowed inside an a in HTML or XHTML.
FIDDLE
You are using a <a> tag, change it to use a <div> tag, or remove <a> tag at all
You can follow this to make div clickable.
I have the simple text: "What is this?" on a HTML page.
Without making it a button, is there a way to simply prompt a message box when the user clicks the text?
The simplest way is using Javascript:
What is this
(The # will make the page jump to the top after the click, but there are ways to prevent it, and some will discourage its usage. The JavaScript can be put on the href as well, but it's not considered good practice.)
But it doesn't necessarily need to be a <a> anchor, it can be any HTML element:
<span onClick="alert('Hello World!');">What is this</span>
If it is not a <a>, <button> or any other element where it is usual to indicate user interaction, you need to stilize it or otherwise indicate it is clickable somehow.
You can add click handler to any element, not only a button.
<span onclick="showMsg()">What is this?</span>
This is a good JavaScript way of doing it:
`<script language=JavaScript>
What is this? "
</script>`
Make sure to put this within the body of the html.
...something along the lines of telling the browser which percent of the page to center to?
Yes you can. If the person has an element with an ID anywhere on the page. For example:
<div id="someId"></div>
Then you can create a link to this page like:
Middle!
The only thing you need to do is choose an Id in the middle.
No, you can't do this without anchors. You would need to access the DOM in order to do a scrollTo or something like that, which is prohibited on different domains. Security being the main reason.
{using Google Chrome web browser; remeber wiki is dynamic and the following URL may get invalid at anytime, the process is still valid though!}
1_ This is the main URL:
https://en.wikipedia.org/wiki/RSA_(cryptosystem)
2_ I want to refer to "A worked example" in the middle of the page
3_ right click on "A worked example" -> Inspect Element -> Edit as HTML
4_ you should see this:
<span class="mw-headline" id="A_worked_example">A worked example</span>
5_ The id is id="A_worked_example". Copy-paste it in the following sentence as follows:
Middle! :
Middle!
6_ There you go:
https://en.wikipedia.org/wiki/RSA_(cryptosystem)#A_worked_example
:)