iFrame src change event detection?

iFrame src change event detection?

Assuming I have no control over the content in the iframe, is there any way that I can detect a src change in it via the parent page? Some sort of onload maybe?
My last resort is to do a 1 second interval test if the iframe src is the same as it was before, but doing this hacky solution would suck.
I’m using the jQuery library if it helps.

Solutions/Answers:

Solution 1:

You may want to use the onLoad event, as in the following example:

<iframe src="http://www.google.com/" onLoad="alert('Test');"></iframe>

The alert will pop-up whenever the location within the iframe changes. It works in all modern browsers, but may not work in some very older browsers like IE5 and early Opera. (Source)

If the iframe is showing a page within the same domain of the parent, you would be able to access the location with contentWindow.location, as in the following example:

<iframe src="/test.html" onLoad="alert(this.contentWindow.location);"></iframe>

Solution 2:

Answer based on JQuery < 3

$('#iframeid').load(function(){
    alert('frame has (re)loaded');
});

As mentioned by subharb, as from JQuery 3.0 this needs to be changed to:

$('#iframe').on('load', function() {
    alert('frame has (re)loaded ');
});

https://jquery.com/upgrade-guide/3.0/#breaking-change-load-unload-and-error-removed

Related:  Better way to call superclass method in ExtJS

Solution 3:

If you have no control over the page and wish to watch for some kind of change then the modern method is to use MutationObserver

An example of its use, watching for the src attribute to change of an iframe

new MutationObserver(function(mutations) {
  mutations.some(function(mutation) {
    if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
      console.log(mutation);
      console.log('Old src: ', mutation.oldValue);
      console.log('New src: ', mutation.target.src);
      return true;
    }

    return false;
  });
}).observe(document.body, {
  attributes: true,
  attributeFilter: ['src'],
  attributeOldValue: true,
  characterData: false,
  characterDataOldValue: false,
  childList: false,
  subtree: true
});

setTimeout(function() {
  document.getElementsByTagName('iframe')[0].src = 'http://jsfiddle.net/';
}, 3000);
<iframe src="http://www.google.com"></iframe>

Output after 3 seconds

MutationRecord {oldValue: "http://www.google.com", attributeNamespace: null, attributeName: "src", nextSibling: null, previousSibling: null…}
Old src:  http://www.google.com
New src:  http://jsfiddle.net/ 

On jsFiddle

Posted answer here as original question was closed as a duplicate of this one.

Solution 4:

The iframe always keeps the parent page, you should use this to detect in which page you are in the iframe:

Html code:

<iframe id="iframe" frameborder="0" scrolling="no" onload="resizeIframe(this)" width="100%" src="www.google.com"></iframe>

Js:

    function resizeIframe(obj) {
        alert(obj.contentWindow.location.pathname);
    }

Solution 5:

Other answers proposed the load event, but it fires after the new page in the iframe is loaded. You might need to be notified immediately after the URL changes, not after the new page is loaded.

Related:  Why is using onClick() in HTML a bad practice?

Here’s a plain JavaScript solution:

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();
}

iframeURLChange(document.getElementById("mainframe"), function (newURL) {
    console.log("URL changed:", newURL);
});
<iframe id="mainframe" src=""></iframe>

This will successfully track the src attribute changes, as well as any URL changes made from within the iframe itself.

Tested in all modern browsers.

Note: The above snippet would only work if the iframe is with the same origin.

I made a gist with this code as well. You can check my other answer too. It goes a bit in-depth into how this works.

Solution 6:

Since version 3.0 of Jquery you might get an error

TypeError: url.indexOf is not a function

Which can be easily fix by doing

$('#iframe').on('load', function() {
    alert('frame has (re)loaded ');
});