Javascript - Input change events inside iframes - javascript

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

Related

Iframe onload event when content is set from srcdoc

How can i specify an onload property for an iframe loaded from srcdoc attribute. For example:
<iframe id="Content" runat="server" srcdoc="Large HTML contents that are set from the server"></iframe>
I'm using asp.net webforms to populate the content from another server.
However, the normal way to trigger onload for an iframe would be the following, but that won't work:
$(function () {
var iframe = document.getElementById(DocumentViewer.GetFrameClientID());
console.log({iframe}) // OK
iframe.onload = function () { // Never Trigger unless i add a src attribute instead of srcdoc
console.log('loaded')
}
})
I found an issue reported on github in 2018 "load" event handler is called prematurely for iframe.srcdoc
Any clue?
the closest thing i've come up with is to call something like this after init.
const interval = setInterval(function() {
var iFrameID = <HTMLIFrameElement>document.getElementById('Content');
if(iFrameID) {
let newheight = iFrameID.contentWindow.document.body.scrollHeight + "px";
iFrameID.style.height = newheight;
}
}, 200);
This sets the iframe height to match that of the iframe's content every 2ms. This function will not terminate and I have not yet found a good stopping condition.

Reset iframe's window object

I have an iframe, without any src specified.
I change the content dynamically with javascript using this code:
let doc = Paste.render_iframe.contentWindow.document
doc.open()
doc.write(Paste.get_value())
doc.close()
Which works. But the only problem is that if some javascript was used before, it stays inside the window object, and redefining them again causes errors.
I haven't found a way to reset/replace the iframe's window object.
What I did before was create a new iframe and replace the old one.
I could also try to change the src and then change the content.
The problem with those is that, 1) replacing iframes very often seems expensive, 2) I would have to deal with race conditions, having to check when iframe is fully loaded to accept new content.
So my question is, is there a way to replace or reset the iframe's window object without replacing it or modifying the src?
Guess I'm going to try changing the src dynamically and waiting for the load event to change the content.
Paste.setup_render = function()
{
Paste.render_iframe.addEventListener("load", function()
{
if(Paste.render_mode)
{
Paste.do_render()
}
})
}
Paste.reset_render_iframe = function()
{
Paste.render_iframe.src = `about:blank?t=${Date.now()}_${Paste.get_random_string(4)}`
}
Paste.render = function()
{
Paste.reset_render_iframe()
}
Paste.do_render = function()
{
let doc = Paste.render_iframe.contentWindow.document
doc.open()
doc.write(Paste.get_value())
doc.close()
}

Set focus on iframe in Chrome

I have an iframe (id: 'chat') with designMode='on' in Chrome.
On Enter keypress event I call the function send(), which takes the iframe contents and writes it to a socket. My problem is that when clearing the iframe, I lose focus.
How to do I set the focus so I can continue to type text in the iframe?
function send(){
var $iframe = $('#chat');
var text = $iframe.contents().text() + "\n";
socket.send(text);
// When this is done, the focus is lost
// If commented, the focus will not be lost
$iframe.contents().find('body').empty();
// My different failed attempts to regain the focus
//$iframe.focus();
//$iframe.contents().focus();
//$iframe.contents().find('body').focus();
//$iframe.contents().find('body').parent().focus();
//$iframe[0].contentWindow.focus();
// I've also tried all the above with timers
//setTimeout( function(){ $('#chat').contents().focus(); }, 100);
}
I've tried many of the solutions on other questions, but none seems to work.
The trick is to first set focus on the body and then create a Range.
var win = iframe.contentWindow;
var range = win.document.createRange();
range.setStart(win.document.body, 0);
range.setEnd(win.document.body, 0);
win.document.body.focus();
win.getSelection().addRange(range);
This question has been answered here
Basically, if you are not refreshing the iframe you could use:
$iframe[0].contentWindow.focus();
Note that I'm grabbing the underlying iframe DOM object.
I have tried below solution it works in all browser (IE/Chrome/Firefox)
Context: I want to focus the iframe all the time.
function IFocus() {
var iframe = $("#iframeId")[0];
iframe.contentWindow.focus();
};
window.setInterval(IFocus, 300);
Hope it helps, if any one in need...
I tested this solution with Chrome. I originally posted it in Setting focus to iframe contents.
Here is code to create an iframe using jQuery, append it to the document, poll it until it is loaded, then focus it. This is better than setting an arbitrary timeout which may or may not work depending on how long the iframe takes to load.
var jqueryIframe = $('<iframe>', {
src: "http://example.com"
}),
focusWhenReady = function(){
var iframe = jqueryIframe[0],
doc = iframe.contentDocument || iframe.contentWindow.document;
if (doc.readyState == "complete") {
iframe.contentWindow.focus();
} else {
setTimeout(focusWhenReady, 100)
}
}
$(document).append(jqueryIframe);
setTimeout(focusWhenReady, 10);
The code for detecting when the iframe is loaded was adapted from Biranchi's answer to How to check if iframe is loaded or it has a content?

Safe way to interact with page's DOM from Overlay JS

I have a Firefox extension that detects whenever a page loads in the browser and returns its window and document. I want to attach some events (that launch functions in my addon's overlay) to elements in the page, but I don't know how to do this in a way that's safe.
Here's a code sample:
var myExt = {
onInit: function(){
var appcontent = document.getElementById("appcontent");
if(appcontent){
appcontent.addEventListener("DOMContentLoaded", this.onPageLoad, true);
}
},
onPageLoad: function(e){
var doc = e.originalTarget;
var win = doc.defaultView;
doc.getElementById("search").focus = function(){
/* ... 'Some privelliged code here' - unsafe? ... */
};
}
};
So can anyone tell me what's the safe way to add these events/interact with the page's DOM?
Thanks in advance!
I think that you want to listen to the focus event, not replace the focus() function:
doc.getElementById("search").addEventListener("focus", function(event)
{
if (!event.isTrusted)
return;
...
}, false);
Usually, there is fairly little that can go wrong here because you are not accessing the page directly - there is already a security layer (which is also why replacing the focus() method will have no effect). You can also make sure that you only act on "real" events and not events that have been generated by the webpage, you check event.isTrusted for that like in the example code. But as long as you don't unwrap objects or run code that you got from the website, you should be safe.

Capture iframe load complete event

Is there a way to capture when the contents of an iframe have fully loaded from the parent page?
<iframe> elements have a load event for that.
How you listen to that event is up to you, but generally the best way is to:
1) create your iframe programatically
It makes sure your load listener is always called by attaching it before the iframe starts loading.
<script>
var iframe = document.createElement('iframe');
iframe.onload = function() { alert('myframe is loaded'); }; // before setting 'src'
iframe.src = '...';
document.body.appendChild(iframe); // add it to wherever you need it in the document
</script>
2) inline javascript, is another way that you can use inside your HTML markup.
<script>
function onMyFrameLoad() {
alert('myframe is loaded');
};
</script>
<iframe id="myframe" src="..." onload="onMyFrameLoad(this)"></iframe>
3) You may also attach the event listener after the element, inside a <script> tag, but keep in mind that in this case, there is a slight chance that the iframe is already loaded by the time you get to adding your listener. Therefore it's possible that it will not be called (e.g. if the iframe is very very fast, or coming from cache).
<iframe id="myframe" src="..."></iframe>
<script>
document.getElementById('myframe').onload = function() {
alert('myframe is loaded');
};
</script>
Also see my other answer about which elements can also fire this type of load event
Neither of the above answers worked for me, however this did
UPDATE:
As #doppleganger pointed out below, load is gone as of jQuery 3.0, so here's an updated version that uses on. Please note this will actually work on jQuery 1.7+, so you can implement it this way even if you're not on jQuery 3.0 yet.
$('iframe').on('load', function() {
// do stuff
});
There is another consistent way (only for IE9+) in vanilla JavaScript for this:
const iframe = document.getElementById('iframe');
const handleLoad = () => console.log('loaded');
iframe.addEventListener('load', handleLoad, true)
And if you're interested in Observables this does the trick:
import { fromEvent } from 'rxjs';
const iframe = document.getElementById('iframe');
fromEvent(iframe, 'load').subscribe(() => console.log('loaded');
Note that the onload event doesn't seem to fire if the iframe is loaded when offscreen. This frequently occurs when using "Open in New Window" /w tabs.
Step 1: Add iframe in template.
<iframe id="uvIFrame" src="www.google.com"></iframe>
Step 2: Add load listener in Controller.
document.querySelector('iframe#uvIFrame').addEventListener('load', function () {
$scope.loading = false;
$scope.$apply();
});
You can also capture jquery ready event this way:
$('#iframeid').ready(function () {
//Everything you need.
});
Here is a working example:
http://jsfiddle.net/ZrFzF/

Categories

Resources