Add CSS to DIV in an Iframe - javascript

I have an Iframe with id="scorm_object".
<iframe id="scorm_object">...</iframe>
Inside this iframe i have a class called framewrap.
I am trying to add CSS to this class like so:
$(document).ready(function() {
$('#scorm_object').contents().find('.framewrap').css('opacity','.2');
});
but I can't seem to get it to work.
I know there are multiple iframe examples on here, but I am really looking for something nice and simple.
Thanks!
Update: Apologies, I have to make this work without jquery.
I have now tried the following:
var iframe = document.getElementsByTagName('iframe')[0];
iframe.addEventListener("load", function() {
window.frames[0].document.body.style.backgroundColor = "#fff";
});
but I get the :
iframe is undefined
error.

Your are firing the JavaScript when the DOM of the parent document is ready. This is likely to happen before the document in the frame is ready.
Waiting for the load event to fire fixed that when I tested it.
Use $(window).on("load", function() { instead of $(document).ready(function() {.

I think this one will work. Change the CSS after iframe loaded
$('#scorm_object').load(function() {
$('#scorm_object').contents().find('.framewrap').css('opacity','.2');
});
If you want to do it in pure javascript you should do something like this. Create an style element and add necessary styles using textContent property and add that style to the of iframe.
var iFrame = document.getElementById("scorm_object");
var style = document.createElement("style");
style.textContent =
'#framewrap{' +
' opacity: 0.2;' +
'}' +
'h1 {' +
' color: green;' +
'}'
;
iFrame.addEventListener ("load", function () {
iframe.contentDocument.head.appendChild(style);
});
The above method doesn't work with cross-domain.
You check this out window.postMessage

Related

Trying to add css styling to iframe with JavaScript

Trying this on Wordpress:
Inside my iframe I have a ._2p3a class I want to change its width to ._2p3a {width: 100% !important;}.
With CSS its not possible to access that class so I am trying with JavaScript:
MY JS CODE:
function hello() {
let myiFrame = document.getElementById("iframe-css");
let doc = myiFrame.contentDocument;
doc.body.innerHTML = doc.body.innerHTML + '<style>._2p3a{width: 100% !important;}</style>';
}
//the iframe id > "iframe-css"
code Source: https://redstapler.co/how-to-apply-css-to-iframe/
The error:
land_page.js?ver=1.0:4 Uncaught TypeError: Cannot read property 'body' of null
at hello (land_page.js?ver=1.0:4)
at HTMLIFrameElement.onload ((index):539)
underlined code:
.body.innerHTML = doc.body.innerHTML + '<style>._2p3a{width: 100% !important;}</style>';
Tried: Using CSS to affect div style inside iframe
(got errors with all examples "None worked").
I am running this function with onload="hello(this)" on my iframe.
Any other suggestions how I can edit that class to make its width 100%??
please try bellow code ... I hope you get result:
let myiFrame = document.getElementById("iframe-css").contentWindow;
let doc = myiFrame.document;
doc.body.innerHTML = doc.body.innerHTML + '<style>._2p3a{width: 100% !important;}</style>';
Adding a <style> element isn't the best way to do this. However, even if it was, you should try to avoid adding elements via innerHTML. It is better to use Document.createElement (document is an instance of Document) and Element.appendChild (all elements are instances of the Element class).
The best way to do this is by directly modifying the style of the elements in the class.
function hello() {
let myiFrame = document.getElementById("iframe-css");
let doc = myiFrame.contentDocument ?? myiFrame.contentWindow?.document ?? new Document();
let elements = doc.getElementsByClassName("2p3a");
for(let i = 0; i < elements.length; ++i) {
elements[i].style.width = "100%";
}
}
Also, the onload attribute sometimes doesn't work on an iFrame. You may have to use the DOM like this:
document.getElementById("iframe-css").onload = hello;
On a side note, you should generally stick to 2 or 4 spaces of indentation in JavaScript, but you chose 3.
Decided to use a different plugin since using the facebook iframe was causing some trouble. With this new plugin everything is working fine so yea.
Thanks to anyone who put effort to answering, I appreciate your help.

Determine when iFrame content is rendered after IFrame has already loaded

Using javascript I'm creating an iframe, adding it to the parent DOM and then writing HTML to it via iFrameEl.contentWindow.document.write()
I need to determine when all content in the iFrame has been rendered after iFrameEl.contentWindow.document.closed() has been called.
The iFrame's onload event appears to be called when the iframe is added to the DOM originally, before I can write to it and I need to add it to the DOM in order to get access to the iFrame's contentWindow.document, so catch 22.
In Chrome, as an alternative I have used the srcdoc attribute to add all the content I need to the iframe and the add the iframe to the dom and wait for the onload event however srcdoc is not supported in IE
var iFrameHTML = '<!DOCTYPE html><html><head>';
iFrameHTML = iFrameHTML + '</head><body>' + htmlIncludingImagesEtc + '</body></html>';
iFrameEl.srcdoc = iFrameHTML;
myDiv.append(iFrame);
iFrameEl.onload = function(){
//proceed
}
I know the iFrame's src attribute can also be used, but the limitation on Data URI characters prevents me from using that approach
I know there are many similar questions on here, but I could not find any that matches my requirements.
I need to dynamically create an iFrame, add content to it and determine when all the content has been rendered, is there some obvious way to achieve this, or will it require MutationObservers etc.?
Check out DOMFrameContentLoaded. It is an event that will be fired when the content in the frame is loaded and parsed.
Late answer, but it may help someone...I found that even after the iframe was added to the DOM, if I added the links to style sheets from the head of the parent DOM to the iframe as a String as follows, it meant that the load event occurred
iFrame$.on('load',function(){
//iFrame loaded
});
var headHTML = '<head>';
$('head link').each(function(index, link) {
headHTML = headHTML + link.outerHTML;
});
headHTML = headHTML + '</head>';
iFrameDoc.open();
iFrameDoc.write("<!DOCTYPE html>");
iFrameDoc.write("<html>");
iFrameDoc.write(headHTML);
iFrameDoc.write("</body>");
iFrameDoc.write("</html>");
iFrameDoc.close();

onclick event handler in javascript code, not html tag

when trying to ensure my webpage is using unobtrusive javascript I cant seem to get the onclick event to work in my javascript, it only works as an event in the html tag. here is the code
var dow = document.getElementById("dowDiv");
dow.onclick=function () {}
any reason that this isnt working for me? as all the answers i can find say this is the way to do it, thanks in advance
There could be several reasons based on the information provided.
Most likely, the event function code is being attached before the DOM has finished loading.
Alternatively, you might be using a browser which doesn't support onclick (though this is unlikely!). To guarantee it will work, you can use fallbacks for the main routes of attaching an event:
if (dow.addEventListener) {
dow.addEventListener('click', thefunction, false);
} else if (dow.attachEvent) {
dow.attachEvent('onclick', thefunction);
} else {
dow.onclick = thefunction;
}
Make sure that you only have one element with the id dowDiv. If you have z-index's on elements and something is over the div it might be blocking the click event on the div.
var dow = document.getElementById("dowDiv");
var out = document.getElementById("out");
var clickCount = 0;
dow.onclick = function() {
clickCount += 1;
out.innerHTML = clickCount
}
<div id="dowDiv">Hello onclick <span id="out"></span>!</div>
You can use jQuery to achieve a simple o'clock function.
Make you include jQuery BEFORE you reference your .js file:
<script src="path/to/jQuery.js"></script>
<script src="file.js></script>
With jQuery you can say
$('#dowDIV').click(function(){
Do stuff here;
})

Making script wait until iframe has loaded before running

The site I'm working on has a Live Chat plugin on an iframe. I'm trying to change an image if there are no agents available. My code works on the console, but nothing on the site.
var LiveChatStatus = $("iframe").contents().find(".agentStatus").html();
if (LiveChatStatus =="Offline"){
$('#liveChat').html('<img src="%%GLOBAL_ShopPath%%/product_images/theme_images/liveoffline.png">');
}
I tried this:
$('iframe').ready(function(){
var LiveChatStatus = $("iframe").contents().find(".agentStatus").html();
if (LiveChatStatus =="Offline"){
$('#liveChat').html('<img src="%%GLOBAL_ShopPath%%/product_images/theme_images/liveoffline.png">');
}
});
And this:
$(document).ready(function(){
var LiveChatStatus = $("iframe").contents().find(".agentStatus").html();
if (LiveChatStatus =="Offline"){
$('#liveChat').html('<img src="%%GLOBAL_ShopPath%%/product_images/theme_images/liveoffline.png">');
}
});
But neither worked
The best solution is to define a function in your parent such as function iframeLoaded(){...} and then in the iframe use:
$(function(){
parent.iframeLoaded();
})
this works cross-browser.
If you cannot change the code within the iframe, your best solution will be to attach the load event to the iframe..
$(function(){
$('iframe').on('load', function(){some code here...}); //attach the load event listener before adding the src of the iframe to prevent from the handler to miss the event..
$('iframe').attr('src','http://www.iframe-source.com/'); //add iframe src
});
Another way to bind to the load event of an iframe is to attach a load listener to the iframe before adding a src tag to the iframe.
Here's a simple example. This will also work with iframes that you don't control.
http://jsfiddle.net/V42ts/
// First add the listener.
$("#frame").load(function(){
alert("loaded!");
});
// Then add the src
$("#frame").attr({
src:"https://apple.com"
})
Found this from Elijah Manor's website which works very well
function iFrameLoaded(id, src) {
var deferred = $.Deferred(),
iframe = $("<iframe class='hiddenFrame'></iframe>").attr({
"id": id,
"src": src
});
iframe.load(deferred.resolve);
iframe.appendTo("body");
deferred.done(function() {
console.log("iframe loaded: " + id);
});
return deferred.promise();
}
$.when(iFrameLoaded("jQuery", "http://jquery.com"), iFrameLoaded("appendTo", "http://appendto.com")).then(function() {
console.log("Both iframes loaded");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Javascript - JQuery - clearInterval/setInterval - iframe cycle won't stop on click

I'm fairly new to Javascript in general, and I cobbled together a small script from things found mostly on this site to try to get a small iframe to cycle through a bunch of links, which it does brilliantly. However, I also want it to stop cycling when the user clicks on the iframe or any of its contents.
Here is the code I have so far. There is only one iframe on the HTML page.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
<!--
var sites = [
"side/html5.html",
"side/silverlight.html",
"side/wordpress.html",
"side/mysql.html",
"side/php.html",
"side/css3.html"
];
var currentSite = sites.length;
var timerId;
var iframeDoc = $("iframe").contents().get(0);
$(document).ready(function ()
{
var $iframe = $("iframe").attr("src","side/html5.html");
timerId = setInterval(function()
{
(currentSite == 0) ? currentSite = sites.length - 1 : currentSite = currentSite -1;
$iframe.attr("src",sites[currentSite]);
}, 4000);
$(iframeDoc).bind('click', function()
{
clearInterval(timerId);
});
});
//-->
</script>
</head>
<body>
<sidebar>
<iframe name="sideframe" src="side/html5.html"></iframe>
</sidebar> ..etc..
Please help, I am trying to learn Javascript as fast as I can but as far as I can see, it should work, but it really doesn't.
Thanks for any help you can give me, it's really appreciated.
EDIT:
Okay, I've got a new script now, mostly based off of Elias' work, but it doesn't work either. I've pinned it down in Firebug and it's saying that the timerCallback.currentSite value IS updating properly, though I can't find the $iframe's src value to check for it explicitly. As far as I can tell, it is updating the variables properly, it's just not updating the iframe properly. Am I calling/setting the iframe correctly in this code? Also, is the linked in jquery library sufficient for my purposes? I'm a little lost of all these libraries to link to...
<script type="text/javascript" src="http://code.jquery.com/jquery.js"></script>
<script type="text/javascript" charset="utf-8">
<!--
var sites =
[
"side/html5.html",
"side/silverlight.html",
"side/wordpress.html",
"side/mysql.html",
"side/php.html",
"side/css3.html"
];
var $iframe = $("iframe").attr("src","side/html5.html");
function timerCallback()
{
timerCallback.currentSite = (timerCallback.currentSite ? timerCallback.currentSite : sites.length) -1;
$iframe.attr("src",sites[timerCallback.currentSite]);
$($('iframe').contents().get('body')).ready(function()
{
$(this).unbind('click').bind('click',function()
{
var theWindow = (window.location !== window.parent.location ? window.parent : window);
theWindow.clearInterval(theWindow.timerId);
});
});
}
var timerId = setInterval(timerCallback, 4000);
//-->
</script>
If I were you, I'd play it safe. Since you say you're fairly new to JS, it might prove very informative.
function timerCallback()
{
timerCallback.currentSite = (timerCallback.currentSite ? timerCallback.currentSite : sites.length) -1;
$iframe.attr("src",sites[timerCallback.currentSite]);
}
var timerId = setInterval(timerCallback, 4000);
$($('iframe').contents().get('body')).unbind('click').bind('click', function()
{
var theWindow = (window.location !== window.parent.location ? window.parent : window);
theWindow.clearInterval(theWindow.timerId);
});
Now I must admit that this code is not tested, at all. Though I think it provides a couple of things to get you on your way:
1) the interval is set using a callback function, because it's just better for tons of reasons
1b) in that Callback, I took advantage of the fact that functions are objects, and created a static var, that is set to either the length of your sites array (when undefined or 0), in both cases 1 is substracted
2) jQuery's ,get() method returns a DOM element, not a jquery object, that's why I wrapped it in $(), a new jQ obj, giving you the methods you need.
3) since you're manipulating the dom inside the iFrame, it's best to unbind events you want to bind
4) inside the iFrame, you don't have direct access to the parent window, where your interval is.
You might want to read up on how to deal with iFrames, because they can be a bit of a faff from time to time
EDIT:
David Diez is right, easiest way around this is to incorporate the binding in the timeout function:
function timerCallback()
{
timerCallback.currentSide = ...//uncanged
//add this:
$($('iframe').contents().get('body')).ready(function()
{
$(this).unbind('click').bind('click',function()
{
//this needn't change
});
});
}
In theory, this should bind the click event to the body after it has been loaded
Edit2
I've been messing around a bit, you could keep your code, as is. just add a function:
function unsetInterval()
{
window.clearInterval(window.timerId);
}
and add this to your setInterval function:
$('#idOfIframe').load(function()
{
var parentWindow = window.parent;
$('body').on('click',function()
{
parentWindow.clearInterval();
});
});
this will get triggered as soon as the iFrame content is loaded, and bind the click event and unset the timer, like you wanted to
I think your code is not working because of this
var iframeDoc = $("iframe").contents().get(0);
This could be getting the header of the iFrame because you are saving the iframeDoc value to the first child of the iframe, the head tag, actually if you have more than 1 iframe in your window iframeDoc would be undefined because $("iframe") gets all the iframes of your document.
BTW your currentSite value condition is wrong, you asign the same value for both conditions
Now I give you an example:
<iframe id="myFrame" src="http://www.google.com/"></iframe>
and the script:
<script type="text/javascript" src="http://code.jquery.com/jquery.js"></script>
<script type="text/javascript">
var sites = [
"site1",
"site2"
];
var myFrame = document.getElementsByTagName('iframe')[0];
var currentSite = myFrame.getAttribute('src');
var timerId;
var myFrameDoc = window.frames[0].document;
$(document).ready(function()
{
myFrame.setAttribute('src', 'side/html5.html');
timerId = setInterval(function()
{
//WRONGG
(currentSite == 0) ? currentSite = sites.length - 1 : currentSite = currentSite -1;
myFrame.setAttribute('src', sites[currentSite]);
$(myFrame).off("click").on("click", clearInterval(timerId));
}, 4000);
//Won't work because you are trying to get events from an inside of a iframe
//$(myFrameDoc).on("click", clearInterval(timerId));
//This may work
$(myFrameDoc).off("click").on("click", clearInterval(timerId));
});
</script>
When you try to track the events of an iframe you have to be carefull because an iframe contains a totally different document for javascript purprouses so basically you have to get inside the new document, unbind the events you need to use, and bind them again against your functionality, as #Elias points out. but be aware that you are changing constantly the src of your iframe, so if yu really need to do that you will have to separate the code that unbinds and binds again your clearInterval, and for that matter maybe $.on() could work for you.
EDIT: Calling to the iframe should work this way IF the src of the iframe is inside the same domain, with the same port and with the same protocol:
var myFrameDoc = window.frames[0].document;
I Added a new variable because we want to bind and unbind the click event to the iframe's document, not to the iframe, we use for that the window.frames collection property, but modern browsers throw an exception and denies acces if you try to access to a frame and you are not on the same domain with using the same port and the same protocol...
Additionaly the use of $.on() and $.off() instead of $.bind and $.unbind() is because the first ones are the new ones and despite we are not using it here, they are capable of watch constantly the DOM for new elements to bind if added; that could be useful to this case if this code still doesn't work. If that is the case you can still change this:
var myFrameDoc = window.frames[0].window;
and this:
$(myFrameDoc).off("click", "document").on("click", "document", clearInterval(timerId));
This will re-bind the event handler to new documents additions. Not tested but could work.

Categories