How to trigger iFrame load within an iFrame? - javascript

I send messages to iFrame, but only on iFrame load event. Want to trigger it manually without page reload, after changing DOM.
Explanation: It is kind of survey and on page change I send page size. Problem happens when I insert new image in DOM, than I need to tell parent page and trigger the iFrame load event. The message goes parent->iframe, than iframe->parent only on iFrame load.

Instead of triggering a load event, you should use a message posted by your IFrame.
JavaScript in outer frame (this attaches an event listener for messages and shows an alert when a message is received):
window.addEventListener('message', function(e) {
// This check can be removed for testing purposes, but for security
// it's strongly recommended that you leave it in there and replace
// the domain with the one of your IFrame's src, to ensure you process
// only messages coming from your own code and not somebody else's.
if(e.origin != "http://yourdomain.com") return;
alert("Got a message: " + e.data);
});
JavaScript in inner frame (this sends a message to the parent window - it should trigger the listener there and show the alert):
// The second parameter can be replaced by "*" for testing, but again it
// is strongly recommended to use the domain you expect the outer frame
// to have, to ensure your message lands in the right window (in case
// another page loaded yours in an IFrame).
window.parent.postMessage("Hello World!", "http://yourdomain.com");
Instead of "Hello World!", you can also pass JS objects.
It also works the other way round: If you install a message listener in your IFrame as well, then you can also send messages from the outer frame to the inner one, using something like document.getElementById('myIframe').contentWindow.postMessage(...).
See also: http://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage

Related

How to fix getting the same document element 'meta' in Google Chrome Extension

I'm developing a new Chrome extension, that return meta of a website. My problem is that I have always the same result, even if the content of web page change. To get the correct and actual meta elements I must to refresh the tab (F5).
The code of my button is :
chrome.tabs.executeScript({file: 'app/js/get_metas.js'});
And the code of my get_metas.js is :
document.head.addEventListener("DOMContentLoaded", getMeta(), true);
function getMeta() {
const meta = document.head.querySelector("meta[property='****']").getAttribute("content");
alert(meta);
}
The result is always the same, I must refresh the page with F5 to get the actual meta element.
If you enter following code in your console you will see the alert immediately:
document.head.addEventListener("DOMContentLoaded", getMeta(), true);
function getMeta() {
alert("test");
}
Reason is that the function will be called immediately. To change that remove the (), and also I believe the event is fired on the document itself (I'm not sure the event traverses down the whole document and the useCapture=true would work). So use something like:
document.addEventListener("DOMContentLoaded", getMeta, true);
It will still only fire once when document is loaded. If you need to run the function after some other event you'd need to add a listener for that event.
If you want to call your function after a change to the document (including ajax navigation) you could look into using Mutation Observers.

How to get reference to elements of an iframe?

Basically a survey from SurveyMonkey is loading on my webpage in an iframe.That survey has 'Done' button which needs to be clicked when you have filled up the survey. Now when i inspect console by right-clicking on page anywhere except survey pop up and execute this statement:
document.getElementsByClassName("btn small done-button survey-page-button user-generated notranslate");
The result i get is:
HTMLCollection []
But when i inspect on survey popup and write the same statement in console i get the following result:
HTMLCollection [button.btn.small.done-button.survey-page-button.user-generated.notranslate]
Basically i want to add an event when 'Done' button will be pressed but the problem is i cannot get reference to this button simply by passing its class because it loads after few seconds later when my html page is loaded.
I have even written a function to alert me 'Hi' when 'Done' button shows up button it is of no value.Here is the code:-
$('.btn small done-button survey-page-button user-generated notranslate').on('load',function(){alert('hi'); console.log("survey-loaded");});
Following is the html of 'Done' button:
<button type="submit" class="btn small done-button survey-page-button user-generated notranslate">DONE</button>
You cannot reference iFrame content from another domain. That will violate the Same-origin policy.
The mere idea of an iFrame is that it blocks you from manipulating its content, so the SurveyMonkey content still considered secured.
You can, however, interact with iFrame via post messages, and you can get a reference to iFrame content if it doesn't violate the same-origin policy.
See similar questions here, and here.
Try to access iframe elements after it is loaded.
document.getElementById('your-iframe-id').onload = function() {
// Create variable for your iframe.
var iframe = document.getElementById("your-iframe-id");
//then access its content like this
var btn document.getElementsByClassName("btn small done-button survey-page-button user-generated notranslate");
//Rest of your code
}
The above code will only works if there is no cross domain restriction
Use a delegate, target a parent element that is always on the page the the addEventListener to it
document.querySelector('your-const- parent- `element-containing-the- button').addEventListener('click',(e)=>{
If(e.target.tagName === 'BUTTON')
'your actions'}
);
I hope this helps #cheers

Stop Safari extension from caching messages

I'm having problems with creating a safari extension that has been causing me headaches.
The problem is this: I have created an extension that gets images from a web page using an injected script. I have a function in the popover that displays the web images and allows the user to click and send the selected image to a backend. This all goes through the global page which handles signals and messages. The scenario is this:
When the popover opens, it sends a signal to the global page to initiate the response (image URLs) from the injected script.
When the global page gets the message from the injected script, it calls the function in the popover passing in the data from the injected script as an argument.
The popover shows all images returned from the global page via the injected script.
The problem is that every time I open the popover, it appends the images from the last call instead of giving a fresh list of images. For instance, on first popover open, I get one image (assuming the page has only one image). If I close the popover and open it again, I get two of the same image. If I close and open the popover a third time, it appends the first image with the one from the second time and gives me 3 of the same image. On the fourth open of the popover I get 1 + 1 + 1 + 1, so 4 images. So it seems to be appending the messages and not giving me a fresh message every time.
My question is: how can I destroy the messages that are being cached after each popover closes? I hope I am being clear. Perhaps something else is happening with my code that I am not aware of. Please help if you can. Here is my code from the global HTML:
function popoverHandler(event) {
//check for popover opening
if (event.target.identifier === "MyPopUp") {
//send message to injected script to send page info
safari.application.activeBrowserWindow.activeTab.page.dispatchMessage("getContent", '', false);
//this works fine, I get this message every time popover opens
console.log('getContent message sent');
//listen for message containing page info from injected script
safari.application.addEventListener('message', function (messageEvent) {
//only get message from current tab
if (messageEvent.name === "pageInfo" && messageEvent.message.url === safari.application.activeBrowserWindow.activeTab.url) {
pageInfo = messageEvent.message;
//the problem seems to be in here. Every time I open the popover, //I get the current page info plus all the page info messages from //the previous time I open the pover, all duplicates of the previous //messges
console.log(pageInfo);
// call a function in the popover, passing the pageInfo data //received from the injected script
safari.extension.popovers[0].contentWindow.onPageDetailsReceived(pageInfo);
}
});
}
}
Ok, so I was able to solve the problem. First of all, I separated the popoverHandler from the eventListener. For some reason, it was firing the function too many times and returning several lists of the same images. The major issue, however, was that in the popover.js, I was storing the list of images as a var. When I removed the var, the data stopped persisting and I was getting a fresh list every time.

iframe submit get the posted content

Using an iframe to post a submit, it has a file upload. everything is working fine up til the returned content.
If i show the iframe on the page, i see the html that was returned from the function in my iframe. Having much trouble getting the content of the iframe to replace the content of the page.
Basically get the content of the body iframe and place it in the body tags of the page.
I'm sure its 1 or 2 lines, but every jquery or document or getElementById idea i've found on the web is not working.
I do notice something odd, if i try to use "console.info('somemessage')" in my reload function, it throws an error saying console does not exist. Not sure why, but seems my javascript focus is in the iframe and can't see firebug.
Heres the code stripped down. Back to trying the .load event, which is working. but its that second line that trys tot write the content to the body. when i comment it out, the iframe shows, with my content. If i run it uncommented, the whole page reloads.
if (isStarted == false) {
isStarted = true;
statustracker.start();
//style="height:0px;width:0px;"
var iframe = $('<iframe name="postframe" id="postframe" class="hidden" />');
$('div#iframe').append(iframe);
$('#ImportDetailForm').attr("target", "postframe")
form.submit();
$("#postframe").load(function () {
iframeContents = $("iframe")[0].contentDocument.body.innerHTML;
$("body").html(iframeContents); // <--- the problem
});
}
In your parent page (the one containing the iframe), you could set an event listener for the 'message' event, like so:
window.addEventListener("message", receiveMessage, false);
function receiveMessage(e) { ... }
Then in your iframe, just post a message to the 'parent' window like this:
parent.postMessage(someString, parentUrl);
Because messages are strings, you'll need to serialize any data you're sending between iframe and parent window - I suggest JSON! So in your case, serialize the returning HTML from the upload request and post it to the parent, then deserialize it on that side and inject it into the DOM.
An invalid or illegal string was specified" code: "12
probably because iframeContents is empty.
$("#postframe").load(function () {
var win = document.getElementById("postframe").contentWindow;
var parent_url = decodeURIComponent(document.location.hash.replace(/^#/, '')), link;
iframeContents = $("#postframe").find("body").contents().serialize(); //$("iframe")[0].contentDocument.body.innerHTML;
console.info(iframeContents);
//$(this).parent("body").html(iframeContents);
win.postMessage(iframeContents, parent_url, parent);
});

Accessing from the page in LowerFrame to the page in UpperFrame causes undefined error!

My website consists of two frames, let's say upperFrame and lowerFrame.
On the document ready of the page in lowerFrame, it access one of textbox located on the page of upperFrame.
Sometimes, since the upperFrame do NOT complete its loading, lowerFrame get the undefined while it access the upperFrame.
Let me know if there are Any solutions/checking to prevent this problem?
How about updating 2 vars in the parent of both frames: topReady and bottomReady. At the top and at the lower frames you set them to call a function that checks if both of them are true. If not it sets the appropriate var to true and once the 2nd frame will be calling the function it will trigger whatever action you want to.
Edit:
Another option is to try and use
$(window.parent.upperFrame).ready(function(){
alert('upperFrame loaded')
});
try jQuery .load() function
The load event is sent to an element
when it and all sub-elements have
been completely loaded. This event can be sent to any element associated
with a URL: images, scripts, frames, iframes, and the window
object.
Here is the sample code
Edited:
put code below in document ready of lower iframe.
$(function(){
$('#UpperIframeID', window.parent.document).load(function(){
var valueOFTextbox = (this).contents().find("#textboxID").val();
});
});
</script>
If it doesn't work in IE then put conditional statement and for IE use .ready() function.

Categories

Resources