Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems with iframe when used more than once on the page

I'm creating a quickview functionality, where you can see the contents of each item in a product listing directly in a modal that will open.

In the modal there is a frame that is generated dynamically with javascript, and I place the url of my controller that renders the modal content (url like this http://localhost/quickview/product/view/id/18564/).

When the modal is closed, I delete the modal content, and when the user wants to see the content of another product on the same page, I re-generate an iframe element with javascript and display.

The problem is that after the first modal view, the iframe loads and displays the content again but the javascript that runs in the iframe (we have an image gallery in the product content) does not work. Soon after the second attempt in front of the gallery and all other behaviors with javascript do not work, although modal, iframe and content coming from the controller are correct.

I already tried to reload the same iframe (without destroying it) and display it again, I tried to create the iframe with id different to each modal view, but I could not solve it once. Below the javascript I use to generate the modal and the iframe. The controller I do not believe is relevant (whenever I open the url of the content in a new tab everything works perfectly, as well as being independent of the product every time I open the modal first, everything loads correctly in the modal).

var ProductInfo = Class.create();
ProductInfo.prototype = {
    settings: {
        'loadingMessage': 'aguarde ...',
        'viewport': document.viewport.getDimensions()
    },

    idframe: 'quick-frame',

    initialize: function(selector, x_image, settings) {
        Object.extend(this.settings, settings);
        this.createWindow();

        var that = this;
        $$(selector).each(function(el, index){
            el.observe('click', that.loadInfo.bind(that));
        })

    },

    createLoader: function() {
        var loader = new Element('div', {id: 'pleaseWaitDialog'});
        var imgLoader = new Element('img', {src: '/js/inovarti/ajax-loader.gif', alt: this.settings.loadingMessage, id: 'loading-quickview-img'});
        var contentLoader = new Element('p', {class: 'loader'});

        contentLoader.setStyle({
            'display': 'block',
            'margin-top': (this.settings.viewport.height/2 - contentLoader.getHeight()/2)+'px',
            'text-align': 'center'
        });

        contentLoader.appendChild(imgLoader);
        loader.appendChild(contentLoader);
        document.body.appendChild(loader);

        $('pleaseWaitDialog').setStyle({
            'position': 'fixed',
            'top':  0,
            'left':  0,
            'width': '100%',
            'height': '100%',
            'display': 'block',
            'opacity': '.8',
            'background': '#FFFFFF',
            'z-index': '99999'
        });
    },

    destroyLoader: function(full) {
        if(full) {
            $('pleaseWaitDialog').remove();
        }
        else {
            if($('loading-quickview-img') != null) {
                $('loading-quickview-img').remove();
            }
            $('pleaseWaitDialog').setStyle({'background-color': '#000000'});
        }
    },

    showButton: function(e) {
        el = this;
        while (el.tagName != 'P') {
            el = el.up();
        }
        $(el).getElementsBySelector('.quickview-ajax')[0].setStyle({
            display: 'block'
        })
    },

    hideButton: function(e) {
        el = this;
        while (el.tagName != 'P') {
            el = el.up();
        }
        $(el).getElementsBySelector('.quickview-ajax')[0].setStyle({
            display: 'none'
        })
    },

    createWindow: function() {
        var qWindow = new Element('div', {id: 'quick-window'});
        qWindow.innerHTML = '<div id="quickview-header" style="width: 100%; text-align: right;"><a href="javascript:void(0)" id="quickview-close"><i class="glyphicon glyphicon-remove"></i></a></div><div class="quick-view-content"></div>';
        document.body.appendChild(qWindow);
        $('quickview-close').setStyle({
            'padding-right': "20px",
            'padding-left': "20px"
        });
        $('quickview-close').observe('click', this.hideWindow.bind(this));
    },

    showWindow: function() {
        var screenWidth, offsetTopModal;
        if(document.body.clientWidth > 1400) {
            screenWidth = 1400;
            offsetTopModal = 100;
        }
        else {
            if(document.body.clientWidth < 768) {
                screenWidth = document.body.clientWidth;
                offsetTopModal = 0;
            }
            else {
                screenWidth = document.body.clientWidth * 0.8;
                offsetTopModal = 100;
            }
        }

        var windowWidth = screenWidth;

        $('quick-window').setStyle({
            'top':  document.viewport.getScrollOffsets().top + offsetTopModal + 'px',
            'left':  document.body.clientWidth/2 - windowWidth/2 + 'px',
            'display': 'block',
            'position': 'absolute',
            'width': windowWidth + 'px',
            'background': '#FFFFFF',
            'padding': '20px 0px',
            'margin-bottom': '20px',
            'border': '1px solid #F0F0F0',
            'z-index': '999999',
            'border-radius': '4px'
        });

        $('pleaseWaitDialog').observe('click', this.hideWindow.bind(this));

        this.resizeIframe($(this.idframe));
    },

    setContent: function(srcUrl) {
        var options = {
            id: this.idframe,
            frameborder: "0",
            scrolling: "no",
            src: srcUrl,
            hspace: "0",
            name: this.idframe+(new Date().getTime()),
            width: "100%"
        };
        var frame = new Element('iframe', options);
        $$('.quick-view-content')[0].insert(frame);
    },

    clearContent: function() {
        $$('.quick-view-content')[0].replace('<div class="quick-view-content"></div>');
    },

    hideWindow: function() {
        this.clearContent();
        this.destroyLoader(true);
        $('quick-window').hide();
    },

    loadInfo: function(e) {
        e.stop();
        var that = this;
        this.createLoader();
        this.clearContent();
        this.setContent(e.element().href);

        Event.observe($(this.idframe), 'load', function() {
            window.quickview.completeInfo();

            setTimeout(function () {
                window.quickview.resizeIframe($(this.idframe));
            },500);
        });
    },

    completeInfo: function () {
        this.destroyLoader(false);
        this.showWindow();
    },

    resizeIframe: function(obj) {
        if(obj) {
            obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
            obj.style.width = "100%";
        }
    }
}

Event.observe(window, 'load', function() {
    window.quickview = new ProductInfo('.quickview-ajax', '.product-image', {
    });
});

I believe it is not relevant, but the application is Magento 1.9.3.9, so I'm using prototype as js framework (native from Magento).

A curious fact, if I update the frame through the browser using the right button and requesting the "Refresh Frame" with mouse, the iframe is updated correctly and the content javascript loads correctly.

UPDATE:

By performing some tests, I noticed that the first time the iframe is loaded, the width of the iframe is detected in js inside iframe. But in the other times that it is created and inserted, the width is detected as zero. Below the tests:

//First open
console.log(document.documentElement.clientWidth);
//output: 1356

//Second open
console.log(document.documentElement.clientWidth);
//output: 0

OwlCarousel2 do a throw (more details in https://github.com/OwlCarousel2/OwlCarousel2/issues/1704), and I think de JS stop with the exception.

Owl.prototype.viewport = function() {
    var width;
    if (this.options.responsiveBaseElement !== window) {
        width = $(this.options.responsiveBaseElement).width();
    } else if (window.innerWidth) {
        width = window.innerWidth;
    } else if (document.documentElement && document.documentElement.clientWidth) {
        width = document.documentElement.clientWidth;
    } else {
        throw 'Can not detect viewport width.';
    }
    return width;
};

Even though I change OwlCarousel2 (the latest version doesn't has a throw), I believe that the fact that the width is being detected incorrectly will generate several other problems. I also updated the iframe by always creating it 100% wide, but the problem still persists.

like image 986
Denis Spalenza Avatar asked Nov 09 '18 02:11

Denis Spalenza


People also ask

Why iframe should not be used?

Iframes Bring Security Risks. If you create an iframe, your site becomes vulnerable to cross-site attacks. You may get a submittable malicious web form, phishing your users' personal data. A malicious user can run a plug-in.

Do iFrames slow down page load?

So, you should not use iframe excessively without monitoring what's going on, or you might end up harming your page performance. To avoid having your iframes slow down your pages, a good technique is to lazy load them (i.e., loading them only when they are required like when the user scrolls near them).

How many iFrames can a page have?

Except that there is a higher resource demand and other performance issues there is no fixed limitation for those tags on one page.

Does iframe affect performance?

Definitely iframe affects the page load performance and also it is not recommended to use iframe for many page security issues perspective. SEO companies strongly discourage iframes. Are now only used for either display of contents with different content-types i.e PDF or might be for some other needs of time.

What's wrong with iframes?

One of the main problems with an iframe has to do with bookmarks and navigation. If you are using it to simply embed a page inside your content, I think that is fine. That is what an iframe is for. However I've seen iframes abused as well.

What is iframe in HTML?

Nada also dabbles in digital marketing, dance, and Chinese. The iframe element (short for inline frame) is probably among the oldest HTML tags and was introduced in 1997 with HTML 4.01 by Microsoft Internet Explorer.

Do iframes slow down a website?

So, you should not use iframe excessively without monitoring what’s going on, or you might end up harming your page performance. To avoid having your iframes slow down your pages, a good technique is to lazy load them (i.e., loading them only when they are required like when the user scrolls near them).

Can I put a JS script inside an iframe?

2.Now if i put my js script inside an iframe. It doesn't work. Please suggest. Getting variables or functions from external script, requires page caching, so accessing this file via dynamic insertion, is impossible without reloading the page for caching its content -- And also reloading the page is not part of this idea.


Video Answer


1 Answers

It is a jQuery cache issue. You should send headers from your server in order to not cache the iframe in the client:

Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0

You can also force a iframe refresh by using:

iframe.contentWindow.location.reload(true);

Update

var nameOrIndex = 'nameOrIndex'; // i.e. 'my_iframe' or '0'
var iFrame = window.frames[nameOrIndex];
if (iFrame) {
    var document = iFrame.contentDocument ? iFrame.contentDocument : iFrame.contentWindow ? iFrame.contentWindow.document : iFrame.document;
    if (document && document.location) {
        document.location.reload(true); // 1 (sandboxing, same domain origin policy)
        document.location.href = document.location.href; // 2 (cross domain, might detect size changes)
    }
    if (iFrame.src) {
        window.frames[nameOrIndex].src = iFrame.src; // 3 (cross domain, might detect size changes)
    }
    $(iFrame).replaceWith($(iFrame).clone()); // 4 (cross domain, might detect size changes)
}

However, regarding your size problem look at this SO question

like image 167
Gillsoft AB Avatar answered Oct 28 '22 20:10

Gillsoft AB