1

I have an iframe that's supposed to load different modules of a web application.

When the user clicks a navigation menu in the top window, it's passes a new url to the iframe. The trouble is, the new url doesn't actually point to a new page, it only uses a changed hash.

i.e.:

  • User clicks "dashboard", iframe src set to application.html#/dashboard
  • User clicks "history", iframe src set to application.html#/history

This means that the iframe does not actually load the src url again because hash changes don't require it to. The application inside the iframe is an angular app which loads the required modules dynamically using requireJS. We need this functionality to remain.

I need to force the frame source to load again even though only the hash changed. It's possible that I instead find a way to rewrite our angular app to dynamically unload/load the modules on push state events but that introduces several layers of issues for the app, plus some IE trouble.

I've tried:

  • Setting iframe src and calling it's location.reload, but that reloads the originally loaded url
  • Setting the iframe location.href/hash and calling reload, same issue
  • Blanking the src attribute and then setting the new url - no effect

The only solution I can find is to set the src to a blank screen, then onload set it to the new url:

var appIFrame = document.getElementById('appIFrame');
appIFrame.src = 'about:blank';
appIFrame.onload = function(){
  appIFrame.src = '// set the real source here';
  appIFrame.onload = false;
}

This works, yet it seems inefficient because there's an extra step.

helion3
  • 27,515
  • 13
  • 48
  • 91
  • This is a little complicated -- especially when considering IE issues. I'll post an answer after finding the solution I came up with about a year or so ago... the code is on github. – Joe Johnson Feb 19 '14 at 21:59
  • Maybe add a dynamic GET parameter – f.e. the current timestamp, which you can get from the JavaScript `Date` object – to the iframe URL. Instead of assigning `application.html#/dashboard` as `src` value, assign `application.html?1234567890#/dashboard` from your outside page (with `1234567890` replaced by the current timestamp, obviously). – CBroe Feb 19 '14 at 22:01
  • Actually, I misread your question initially. I remember researching what you're talking about ... about a year ago. Its inefficient, to be sure, but -- its the only cross-browser (+ versions) solution I've seen so far. – Joe Johnson Feb 19 '14 at 22:05
  • @CBroe I had considered a "cache-busting" style query string but haven't tried it. I'll give that a shot – helion3 Feb 19 '14 at 22:09
  • @CBroe Using a query string like a cache bust seems to work. I'll need to test it cross-browser but if you want to make this an answer, I'll accept – helion3 Feb 19 '14 at 23:08

3 Answers3

4

Maybe add a dynamic GET parameter – f.e. the current timestamp, which you can get from the JavaScript Date object – to the iframe URL.

Instead of assigning application.html#/dashboard as src value, assign application.html?1234567890#/dashboard from your outside page (with 1234567890 replaced by the current timestamp, obviously).

CBroe
  • 82,033
  • 9
  • 81
  • 132
  • Thanks. I really should have tried this when I first thought about it, my js solution was more convoluted. – helion3 Feb 19 '14 at 23:46
0

I don't have a specific answer for you. However, the following script may proved useful (I wrote this about a year or so ago). The following script deals with re-adjusting iframe height when the document changes. This script was tested cross-browser. It does deal with the issues you're experience but indirectly. There is a lot of commenting with the Gist:

https://gist.github.com/say2joe/4694780

Joe Johnson
  • 1,717
  • 13
  • 19
  • Actually, I misread your question initially. I remember researching what you're talking about ... about a year ago. Its inefficient, to be sure, but -- its the only cross-browser (+ versions) solution I've seen so far. – Joe Johnson Feb 19 '14 at 22:06
0

Here my solution (based on this stackoverflow answer):

var $ = function(id) { return document.getElementById(id); };

var hashChangeDetector = function(frame, callback) {

    var frameWindow = frame.contentWindow || frame.contentDocument;

    // 'old' browser
    if (! "onhashchange" in window) {
        var detecter = function(callback) {
            var previousHash = frameWindow.location.hash;
            window.setTimeout(function() {
                if (frameWindow.location.hash != previousHash) {
                    previousHash = frameWindow.location.hash;
                    callback(previousHash);
                }
            }, 100);
        };
    }
    else // modern browser ?
    {
        var detecter = function(callback) {

            frameWindow.onhashchange = function () {
                callback(frameWindow.location.hash);
            }
        };
    }

    detecter(callback);

};

hashChangeDetector($('myframe'), function(hash) {
    alert ('detecting hash change: ' + hash);
});

You can test this here: http://paulrad.com/stackoverflow/iframe-hash-detection.html

Community
  • 1
  • 1
Paul Rad
  • 4,634
  • 1
  • 19
  • 20
  • It's not the hash change I need to detect, I'm actually causing the hash change through javascript and would already know when it occurs. The issue is that a hashchange doesn't force a reload of the iframe `src`. I *could* add pushstate/hashchange events inside the iframe, but that means I need to find ways to un-load modules, etc. – helion3 Feb 19 '14 at 23:03