[javascript] 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.

This question is related to javascript jquery iframe onload

The answer is


Here is the method which is used in Commerce SagePay and in Commerce Paypoint Drupal modules which basically compares document.location.href with the old value by first loading its own iframe, then external one.

So basically the idea is to load the blank page as a placeholder with its own JS code and hidden form. Then parent JS code will submit that hidden form where its #action points to the external iframe. Once the redirect/submit happens, the JS code which still running on that page can track your document.location.href value changes.

Here is example JS used in iframe:

;(function($) {
  Drupal.behaviors.commercePayPointIFrame = {
    attach: function (context, settings) {
      if (top.location != location) {
        $('html').hide();
        top.location.href = document.location.href;
      }
    }
  }
})(jQuery);

And here is JS used in parent page:

;(function($) {
  /**
   * Automatically submit the hidden form that points to the iframe.
   */
  Drupal.behaviors.commercePayPoint = {
    attach: function (context, settings) {
      $('div.payment-redirect-form form', context).submit();
      $('div.payment-redirect-form #edit-submit', context).hide();
      $('div.payment-redirect-form .checkout-help', context).hide();
    }
  }
})(jQuery);

Then in temporary blank landing page you need to include the form which will redirect to the external page.


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

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

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


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

_x000D_
_x000D_
new MutationObserver(function(mutations) {_x000D_
  mutations.some(function(mutation) {_x000D_
    if (mutation.type === 'attributes' && mutation.attributeName === 'src') {_x000D_
      console.log(mutation);_x000D_
      console.log('Old src: ', mutation.oldValue);_x000D_
      console.log('New src: ', mutation.target.src);_x000D_
      return true;_x000D_
    }_x000D_
_x000D_
    return false;_x000D_
  });_x000D_
}).observe(document.body, {_x000D_
  attributes: true,_x000D_
  attributeFilter: ['src'],_x000D_
  attributeOldValue: true,_x000D_
  characterData: false,_x000D_
  characterDataOldValue: false,_x000D_
  childList: false,_x000D_
  subtree: true_x000D_
});_x000D_
_x000D_
setTimeout(function() {_x000D_
  document.getElementsByTagName('iframe')[0].src = 'http://jsfiddle.net/';_x000D_
}, 3000);
_x000D_
<iframe src="http://www.google.com"></iframe>
_x000D_
_x000D_
_x000D_

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.


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

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.

Here's a plain JavaScript solution:

_x000D_
_x000D_
function iframeURLChange(iframe, callback) {_x000D_
    var unloadHandler = function () {_x000D_
        // Timeout needed because the URL changes immediately after_x000D_
        // the `unload` event is dispatched._x000D_
        setTimeout(function () {_x000D_
            callback(iframe.contentWindow.location.href);_x000D_
        }, 0);_x000D_
    };_x000D_
_x000D_
    function attachUnload() {_x000D_
        // Remove the unloadHandler in case it was already attached._x000D_
        // Otherwise, the change will be dispatched twice._x000D_
        iframe.contentWindow.removeEventListener("unload", unloadHandler);_x000D_
        iframe.contentWindow.addEventListener("unload", unloadHandler);_x000D_
    }_x000D_
_x000D_
    iframe.addEventListener("load", attachUnload);_x000D_
    attachUnload();_x000D_
}_x000D_
_x000D_
iframeURLChange(document.getElementById("mainframe"), function (newURL) {_x000D_
    console.log("URL changed:", newURL);_x000D_
});
_x000D_
<iframe id="mainframe" src=""></iframe>
_x000D_
_x000D_
_x000D_

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.

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.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to iframe

Getting all files in directory with ajax YouTube Autoplay not working Inserting the iframe into react component How to disable auto-play for local video in iframe iframe refuses to display iFrame onload JavaScript event YouTube iframe embed - full screen Change New Google Recaptcha (v2) Width load iframe in bootstrap modal Responsive iframe using Bootstrap

Examples related to onload

iFrame onload JavaScript event Execute write on doc: It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened. How to run function in AngularJS controller on document ready? Cannot set property 'innerHTML' of null Javascript onload not working Trying to fire the onload event on script tag How to execute AngularJS controller function on page load? Add Class to Object on Page Load How to run a function when the page is loaded? jquery get height of iframe content when loaded