How can I get Iframe event before load? - javascript

In my site, I use an iframeA in an iframeB, and, when the iframeA changes it's content I have to set the src. I can set it only with the onload event, but this called when the site is loaded. I am looking for some event or trigger, that helps me detect the location/src change before it starts loading. I don't want to wait the whole page load, before the src set. I have no direct access to iframeA (just the script below)
Some code:
var myframe = document.getElementById('frameB').contentWindow.document.getElementById('frameA');
myframe.onload=function (funcname) {...};

Check this gist or my answer to this question. The code there does exactly that:
function iframeURLChange(iframe, callback) {
var unloadHandler = function () {
// Timeout needed because the URL changes immediately after
// the `unload` event is dispatched.
setTimeout(function () {
callback(iframe.contentWindow.location.href);
}, 0);
};
function attachUnload() {
// Remove the unloadHandler in case it was already attached.
// Otherwise, the change will be dispatched twice.
iframe.contentWindow.removeEventListener("unload", unloadHandler);
iframe.contentWindow.addEventListener("unload", unloadHandler);
}
iframe.addEventListener("load", attachUnload);
attachUnload();
}
It utilizes the unload event. Whenever a page is unloaded, a new one is expected to start loading. If you listen for that event, though, you will get the current URL, not the new one. By adding a timeout with 0 milliseconds delay, and then checking the URL, you get the new iframe URL.
However, that unload listener is removed each time a new page is loaded, so it must be re-added again on each load.
The function takes care of all that, though. To use it, you only have to do:
iframeURLChange(document.getElementById("myframe"), function (url) {
console.log("URL changed:", url);
});

What will be changing the source of the iframe? If you have access to that code then you can do whatever is in your onload function then.
If a link has it's target attribute set to the iframe and that is how the source is changing then you can hi-jack the link clicks:
$('a[target="frameB"]').bind('click', function () {
//run your onload code here, it will run as the iframe is downloading the new content
});
Also, just a side-note, you can bind an event handler for the load event in jQuery like this:
$('#frameB').bind('load', function () {
//run onload code here
});
UPDATE
SITE -> frameB -> frameA
$("#frameB").contents().find("#frameA").bind('load', function () {
//load code here
});
This selects the #frameB element (that is in the current top level DOM), gets it's contents, finds the #frameA element, and then binds an event handler for the load event.
Note that this code must be run after #frameB is loaded with the #frameA element already present in it's DOM. Something like this might be a good idea:
$('#frameB').bind('load', function () {
$(this).contents().find('#frameA').bind('load', function () {
//run load code here
});
});
UPDATE
To hi-jack links in the #frameB element:
$('#frameB').contents().find('a[target="frameA"]').bind('click', function () {
/*run your code here*/
});
This will find any link in the #frameB element that has its target attribute set to frameA and add a click event handler.
And again, this will only work if the #frameB iframe element has loaded (or atleast gotten to the document.ready event) so you can select it's elements.

You could also try taking the approach of detecting when your iframe is going to leave its current location. This may be useful in some situations. To do this, put the following code in you iFarme source.
$(window).on('beforeunload', function () {
alert('before load ...');
});

I think adding inline onload attribute with appropriate event handler to iframe tag will solve your problem.
function onIframeLoad(){
//Write your code here
}
Markup change
<iframe src='..' onload='onIframeLoad()' />

Related

Run Code After Squarespace Popup Event Listener/Trigger

I need to run some custom JS after the modal popup is loaded into the viewport. What's the best way to piggy-back onto whatever event is triggered?
Once the pop-up is loaded, I need to execute something like this:
jQuery(".newsletter-form[data-form-id='34li2j4j32il13l2j13ijl21i'] button").click(function (){
console.log("Someone clicked the popup newsletter button.")
});
Because Squarespace doesn't provide the ability to hook into its own methods, we must use multiple Mutation Observers, the second being setup within the first. Adding something like this via Sitewide Footer Code Injection should work:
<script>
(function() {
new MutationObserver(function(m1,o1) {
var popup = document.querySelector(".sqs-popup-overlay");
if (popup) {
o1.disconnect();
new MutationObserver(function(m2,o2) {
var btn;
if (popup.classList.contains("visible")) {
o2.disconnect();
btn = popup.getElementsByTagName("button")[0];
btn.addEventListener("click", function() {
console.log("Someone clicked the popup newsletter button.");
});
}
}).observe(popup, {attributes:true, attributeFilter:['class']});
}
}).observe(document.body, {childList:true});
})();
</script>
The first mutation observer observes the body for the addition of the popup overlay element. If/When that element exists, the first mutation observer is disconnected and a second one is set to observe the class attribute of the popup until it contains the class "visible". If/When that happens, the second mutation observer can be disconnected and an event listener added to the popup submission button. Within the callback function of that event listener, your code is executed.

JS not executing on page loaded with .load

I'm working on a single page application website. All the navigation happens inside a div. I use addEventListener click to find the link, prevent regular href and open it inside the div.
With this code I can change pages, keeping the head and footer without refresh the entire page.
var spa_array = Array.from(document.getElementsByClassName('spa')); // Array with history (for the back button)
spa_array.forEach( function(b) {
var id = b.id;
b.addEventListener('click', function(e) {
event.preventDefault(); // Prevent href
history.pushState({id:id}, null, id); // Change url on browser
openPage(id);
});
});
window.addEventListener('popstate', function(e) {
openPage(e.state.id);
});
function openPage(url) {
var encodedUrl = encodeURI(url);
$("#spa").load(encodedUrl); // open link inside the div
}
This is where the problem happens: I use JS to load a new page on the div, index_2.html for example. The links on index_2.html page will not trigger the JS addEventListener, so it will refresh the page and open the new link.
JS is not being applied to the page opened inside the .load. Is there a way to apply the same script, without calling it again (which causes many a lot of trouble)?
Use a delegated event handler:
$("#spa").on('click', '.spa', function(e){
var anchor = this,
id = anchor.id;
e.preventDefault();
history.pushState({id:id}, null, id);
openPage(id);
});
You can register the handler on a DOM node that does not get removed (in your case, the container whose contents change, but the element itself stays the same), and pass in a selector as a second argument to check if the click occurred on an element inside it that matches the selector.
This is necessary because once you .load() additional content it will replace whatever was there in the element before, including any event listeners that you attached, once, on first load. You'd need to call your loop each time the content is changed, but this is a much less resource intensive solution that will save you the hassle.
I would extract the logic for adding the event listeners as shown below:
function bindLinks() {
var spa_array = Array.from(document.getElementsByClassName('spa'));
spa_array.forEach( function(b) {
var id = b.id;
b.addEventListener('click', function(e) {
event.preventDefault(); // Prevent href
history.pushState({id:id}, null, id); // Change url on browser
openPage(id);
});
});
}
That way you can call bindLinks() after the html is loaded into your div. You can do that by passing it as the second argument to .load().
function openPage(url) {
var encodedUrl = encodeURI(url);
$("#spa").load(encodedUrl, bindLinks);
}

Hiding a DIV in a JQuery Overlay Window

Taking from the code found here: http://jquerytools.org/demos/overlay/external.html
I got my popup window to work and everything but I wanted to prevent my header from displaying in the overlay popup window. I've added $('#header').hide(); to the script below but its not working. Sorry Im not too familiar with javascript. Any help would be great!
$(function () { // if the function argument is given to overlay,
// it is assumed to be the onBeforeLoad event listener
$("a[rel]").overlay({
mask: 'grey',
effect: 'apple',
onBeforeLoad: function () {
// grab wrapper element inside content
var wrap = this.getOverlay().find(".contentWrap");
// load the page specified in the trigger
wrap.load(this.getTrigger().attr("href"));
$('#header').hide();
}
});
});
I just did a quick test, and I think the issue is that you're trying to hide the header before it renders on the page. The overlay configuration has another event called onLoad, which would be a better place to ensure that the loading of the external content has happened.
Try this code:
$(function() {
// if the function argument is given to overlay,
// it is assumed to be the onBeforeLoad event listener
$("a[rel]").overlay({
mask: 'grey',
effect: 'apple',
onBeforeLoad: function() {
// grab wrapper element inside content
var wrap = this.getOverlay().find(".contentWrap");
// load the page specified in the trigger
wrap.load(this.getTrigger().attr("href"));
//at this point, the page is still loading the external content, so it's not available to hide yet
},
onLoad: function() {
$('#header').hide();
}
});
});
I'm not familiar with this plugin, but two things:
If you want to do this every time, it's not dynamic. So put it in your CSS file.
You define this in "onBeforeLoad", so it is already "hide". Maybe there is a function would works better in this case.

Jquery bind()/live() within a function

I wrote a little pager which removes and rewrites content. I have a function called after loading the page, it shall be executed after changing the page as well. Because I do not wat to implement the function twice (on initialisation and after changing the page) I tried bind()/live() and a simple function.
The function looks like this:
jQuery('.blogentry').each(function (){
jQuery(this).click(function(){
//Clicking on the element opens a layer, definitely works - I tested it
});
});
It is executed after initialisation, for executing it after page changes as well I tried the following:
jQuery('.nextPage, .prevPage').click(function changePage(){
// Changing page and rewriting content
showEntry();
});
//...
showEntry();
//...
function showEntry(){
jQuery('.blogentry').each(function (){
jQuery(this).click(function(){
//Clicking on the element opens a layer, definitely works - I tested it
});
});
}
But the function is not executed if put inside a function (lol) and called via showEntry();
Afterwards I tried to bind the function...
jQuery('.nextPage, .prevPage').click(function changePage(){
// Changing page and rewriting content
jQuery('.blogentry').bind("click", showEntry);
});
//...
jQuery(this).click(function showEntry(){
//Clicking on the element opens a layer, definitely works - I tested it
});
Did not work either. Code after the bind()-line would not execute as well.
I thought maybe it's a problem to bind to an event function, if an event is already given via the parameter so i also tried this:
jQuery('.nextPage, .prevPage').click(function changePage(){
// Changing page and rewriting content
jQuery('.blogentry').bind("click", showEntry);
});
//...
function showEntry(){
//Clicking on the element opens a layer, definitely works - I tested it
});
}
No success at all. Maybe I cannot call the function from inside the function regarding to the bind()? Maybe I just do not understand the bind()-function at all? I also tried the live() function since it seemed to fit better, as I am rewriting the content all the time. But it had the same effect: none...
The simplest way to implement this should be
jQuery('.blogentry').live('click', function() { /* onclick handler */ });
This should bind the function to every blogentry on the page at the moment of the call and all the blogentries that are added to the page later on.
Additional notes:
In $(foo).each(function() { $(this).click(fun); }); the each is unnecessary - $(foo).click(fun); is enough.
$(foo).bind('click', fun); is functionally equivalent to $(foo).click(fun) - it does not matter which one you use.
You can use delegate or bind. don't call the function like that, just create a delegate with .blogentry and it should update even after you load a new page via ajax. It will automatically do this.
$("#blogcontainer").delegate(".blogentry", "click", function(){ //open layer });
This should work for you
$(body).delegate(".blogentry", "click", function(){
showEntry();
});
alternaltivly you can use event delegation
$(document).ready(function () {
$('#blogcontainer').click( function(e) {
if ( $(e.target).is('.blogentry') ) {
// do your stuff
}
});
});
hence, no need to bind each blogentry at creation or reload, and it's (slightly) faster.

How to change the src and reload an iframe with DOJO?

I want to click on a link, pull the src of the link, and use that src to refresh an iframe in my page.
dojo.ready(function() {
dojo.query(".link").onclick(function(e) {
var node = e.target;
var url = dojo.attr(node, "href");
document.getElementById("audioiframe").src = url;
dojo.stopEvent(e);
});
});
I could do this quickly in OG Javascript or jQuery, but need to use DOJO.
Thank you
UPDATE: After incorporating Strife25 answer my code is:
dojo.ready(function() {
dojo.query(".audiolink").forEach(function(link){
dojo.connect(link, "onclick", null, function(e){
var node = e.target;
var url = dojo.attr(node, "href");
dojo.query("#audioiframe").attr("src", url);
dojo.stopEvent(e);
});
});
});
The event is attached to the links, the iframe src attribute is updated, but the onclick event is not canceled and the page behaves as if the link is clicked. It appears as if dojo.stopEvent(e); is not working (asking where to download the MP3 File). Also, the iframe is not reloading but I believe that is due to the click not being canceled.
UPDATE:
I am the bug, not the code! I was linking to the MP3 versus the page that housed the MP3 (long story). It works. Thank you.
You're attaching the click event in the wrong way, you should use dojo.connect to attach event handlers. Also, dojo.query() returns a NodeList when it runs instead of a single node.
The proper way to use dojo in this instance would be:
dojo.query(".link").forEach(function(link){
dojo.connect(link, "onclick", null, function(e){
//do your stuff
});
});
If you only have one button that performs the onclick event you are proposing, you should instead use dojo.byId like so:
var link = dojo.byId("linkId"); //retrieves a reference to a DOM node with the given id
dojo.connect(link, "onclick", null, function(e){
//do you stuff
});
Here is the doc page of dojo.connect, which also explains how you can clean up event handlers on object destruction / page unload: http://www.dojotoolkit.org/reference-guide/dojo/connect.html

Categories