I have a textarea box where the user inputs HTML and it gets output into the body element of an iframe.
This works just fine using most HTML tags, but if you use the <script> tag (in order to add JavaScript), the script element does not get transferred to the iframe.
For example, I should be able type the following in the textarea:
<script>
function test() {
alert('test');
}
</script>
<button onclick="test()">test</button>
The button gets added to the iframe but since the script element apparently doesn't, clicking the button does not fire the alert().
One work-around for this is to declare alert() on the button click, rather than using a pre-scripted function; this work-around is shown below:
<button onclick="alert('test')">test</button>
However this only allows one javascript command (whereas the user may want to use a function with multiple commands).
You can see the webpage here
The JavaScript to fill the iframe contents is:
(function () {
$('.grid').height($(window).height());
var frame = $('iframe'),
contents = frame.contents(),
body = contents.find('body'),
styleTag = contents.find('head')
.append('<style></style>')
.children('style');
$('textarea').focus(function () {
var $this = $(this);
$this.keyup(function () {
if ($this.attr('id') === 'html') {
body.html($this.val());
} else {
styleTag.text($this.val());
}
});
});
})();
The problem is any "user-generated" scripts will be executed in the parent window's global context (which the iframe cannot [normally] access). The console shows the following error when clicking the button because the test() function is not accessible scope-wise for the iframe:
Uncaught ReferenceError: test is not defined
To fix this, scripts need to add functions to the global scope of the iframe's internal window:
<script>
(function () {
'use strict';
var iframe = document.getElementById('iframe'), //grab the iframe
win = iframe.contentWindow; //get the window of the iframe
win.test = function () { //declare function in scope of iframe's window
alert('test'); //now "test" will fire because it's defined in a scope accessible to the iframe
};
}());
</script>
<button onclick="test()">test</button>
Related
I want to send some data via postMessage from a page to another one which have different domains. However, I cannot achieve that since the code inside $(yo.document).load never runs; I tried the commented version as well. Here is my code:
<a onclick="popupCenter('http://localhost:58810');" href="javascript:void(0);">CLICK</a>
<script>
function popupCenter(url) {
const yo = window.open(url);
$(yo.document).load(function() {
//yo.document.onload = function() {
console.log("yo loaded");
yo.postMessage("Hello mate", "*");
});
}
</script>
</body>
</html>
The new window opens normally, however the callback inside load is not called. Any ideas?
I have a blank page with an iframe that displays a form from an external domain outside my control. I'm trying to write a bit of Javascript/jQuery that will close the window after the form is submitted.
Here's my code:
<body>
<script>
$('iframe input[type="submit"]').on('click', function () {
window.close();
});
</script>
<iframe src="SomeOtherDomain.com"></iframe>
</body>
Nothing happens when I click the button though. What am I doing wrong?
EDIT:
I'm not sure if it makes a difference or not but it looks like the iframe calls a second iframe... I've got an iframe inside an iframe.
I believe you need to provide some time(100 ms) to submit the form data. Please try this by calling the deleteIframeTimer
function deleteIframeTimer(){
var t = setTimeout("deleteIframe()", 100);
}
function deleteIframe() {
var iframe = parent.document.getElementById("myframe");
iframe.parentNode.removeChild(iframe);
}
So long as your iframe src is from the same domain this will work:
$(document).ready(function () {
var f = $('#myframe')[0];
var win = f.contentWindow;
//Created test environment in IFrame with ID "myframe"
$(win.document.body).append('<form><input type="submit" value="click me"/></form>');
$(win.document).on('submit', function () {
setTimeout(function () { $(f).remove(); }, 1000)
});
});
Simply remove the element but remember you can't get the contentDocument from an iframe that is not of the same domain.
Working solution:
https://jsfiddle.net/f3eayurw/
I'm trying to call iframe2 function from iframe1
document.getElementById('cDiv').contentWindow.toggle_main();
var iframe = document.getElementsByTagName('iframe')[1];
iframe.contentWindow.myFunction();
The console is returning Uncaught TypeError: Cannot read property 'contentWindow' of undefined
I have also tried:
window.frames['iframe2'].toggle_main();
The function in iframe2 is called:
<script>
window.myFunction = function(args) {
alert("called");
}
</script>
The iframes are defined as:
<DIV id="cgDiv">
<IFRAME id="contentGenerator" SCROLLING="No" name ="iframe1" src="outlook.html">
</IFRAME>
</DIV>
<DIV id="cDiv">
<IFRAME id="content" SCROLLING="AUTO" verticalscrolling="yes" NAME = "iframe2" src="index.html">
</IFRAME>
</DIV>
Ideas on where the problem should be?
Javascript can't access functions in an IFrame directly. IFrames can access functions in their parent though.
So if your main page exposes a method RegisterCallback for instance, the IFrame can call it with one of its functions as parameter. The page can then store a reference to the function and call it at another time (with any parameters...)
UPDATE: Added example code
The code below is two files; index.html which is the master page with iframe(s), and child.html which is the page inside the iframe(s).
I've committed the example to github and you can test it by following this link. Due to browser security restrictions the code must be loaded from the same webserver and doesn't work if run directly from the filesystem.
I've intentionally included the child iframe twice to illustrate that any number of children can be registered with this technique. I leave it as an excercise to the reader to add a third iframe... :)
index.html
<html>
<body style="background:#efe">
<h1>This is the master page</h1>
<p><button id="setChildButton" type="button">Make child blue</button></p>
<iframe src="child.html"></iframe>
<iframe src="child.html"></iframe>
</body>
</html>
<script>
var childCallbacks = [];
function registerChild(callback){
console.log('Registering child callback');
childCallbacks.push(callback);
}
function onButtonClick(){
for (var i=0; i < childCallbacks.length; i++){
var callback = childCallbacks[i];
callback('blue');
}
}
window.onload = function(){
document
.getElementById('setChildButton')
.addEventListener('click', onButtonClick);
};
</script>
The javascript has a function registerChild() that it never calls itself, but can be called from child pages to register their endpoints.
When the button is clicked, all registered callbacks are called with the string "blue". It is then up to the childs endpoint to do something good with that. In this case changing its own background color.
child.html
<html>
<body id="childBody" style="background:#fee">
<h2>This is the child page</h2>
</body>
</html>
<script>
function setBackground(color){
var body = document.getElementById('childBody');
body.style.backgroundColor = color;
}
window.onload = function(){
if (parent && parent.registerChild){
console.log('registering with parent');
parent.registerChild(setBackground);
}
};
</script>
The javascript of the child checks if there is a parent (it is running inside an iframe) and that the parent provides a function called registerChild(). It then calls that function with a reference to its own function setBackground().
When the parent later calls the callback with the string "blue", it turns around and sets its own bodys background color to that value.
If all your documents share same origin, it should work, so calling
window.parent.frames['other frame name'].contentWindow['func']()
from within some frame will invoke func from neigbour iframe.
Behold hacky simplistic datauri example in Firefox (Chrome considers dataURI documents as always different origin, so it raises security exception)
data:text/html;charset=utf-8,<iframe id="a" src="data:text/html,<h1 id=a>0</h1><script>function inc(){a.innerHTML++}</script>"></iframe><iframe id="b" src="data:text/html,<button onclick=window.parent.frames.a.contentWindow['inc']()>inc in prevous frame</button>"></iframe>
// First iframe called (ifr_url) in Master page.
// Second iframe called (ifr_tab5) inside the master page.
// I want to call function (Hallow()) in second iframe.
var win = document.getElementById("ifr_url"); // reference to iframe's window
var doc = win.contentDocument? win.contentDocument : win.contentWindow.document;
var form = doc.getElementById('ifr_tab5').contentWindow.Hallow();
I have an HTML page say main.html which has an iframe (say id="myFrame")showing child.html page. Both of these pages have a button called "Hide frame". The onclick of these buttons calls hideFrame() JS function which is declared in main.js file. The hideFrame() function just change the display of myFrame to "none".
function hideFrame(){
document.getElementById("myFrame").style.display = "none";
}
The myFrame is in main.html file so the button in main.html when calls the hideFrame() function, it works. The frame gets hidden. But the same is not working if I call the function from child.html page.
How can I access this element (myFrame) form child.html page?
you should use the main.html's window object to assign the function to. So instead of
function hideFrame(){
document.getElementById("myFrame").style.display = "none";
}
you would do something like
window.hideFrame = function(){
document.getElementById("myFrame").style.display = "none";
}
Now the function is globally scoped on main.html's window.
The child frame has it's own window object. You need access to the parent window object to call the function from child.html.
From main.html, you can call hideFrame normally on click onclick = hideFrame(), but in child.html, you should put onclick = window.parent.hideFrame()
Instead of using an iFrame, I would use jquery to load in segments of html files from other files.
If that is not possible, you could inject Javascript code into the child frame that references objects in the parent. Ex:
child:
<script>
var x;
</script>
parent:
<script>
$("#myFrame").x = function(){
functionality / reference definitions
}
</script>
It took a while to understand what you are saying. From what I understand, you want to get access to an element on the top window from inside an iframe. Here is what to get access to the parent window:
var _parent = window.parent,
_parent_dom = _parent.document;
Then to get access to an element from the parent page (in this case #myFrame):
var my_frame = _parent_dom.getElementById("myFrame");
Is it possible to detect input change events inside an iframe?
The code needs to be pure Javascript and sit outside the iframe. Everytime I type in an input field INSIDE the iframe, the function needs to fire - is this possible??
Try this code:
window.onload = function() {
var iframe = document.getElementsByTagName('iframe')[0];
iframe.onload = function() {
var input = iframe.contentDocument.getElementsByTagName('input')[0];
input.addEventListener('keypress', function() {
// wait until key is entered into input box
setTimeout(function() {
console.log(input.value);
}, 10);
}, false);
};
};
If you are working on the same domain you have access to the iframe.
document.getElementById('yourIframe').contentWindow.document.findElementsByTagName('input')[0].onkeyup = function () {
console.log('Input has changed.');
};
If you are on a different domain you best bet is the postMessage API desribed here: http://davidwalsh.name/window-postmessage
The consequence for this solution is, you'll have to write JS on both sides, the iframe and the parent frame.
document.getElementById('rw_iframe').contentWindow.document.getElementById("fieldID").onchange = function () {
};
Using jquery changes the current context, as long as you use js to attach an event to iframe elements, it will work