Chrome Object tags load multiple times when setting style position: absolute
Asked Answered
B

1

8

Having some trouble sorting through the correct approach to handling the load event in Chrome when loading HTML objects.

I'm using HTML objects to load widgets into a web based dashboard and the load event looks to be broken in Chrome, as I get repeat firing of the load event but only if I set the style on the object in the load event to position:absolute. Unfortunately for my application this is a critical feature as I need to place the widget at specific screen locations using javascript.

The fiddle below will put Chrome in an infinite loop while it only fires once in other browsers (although in my app Chrome fires the load event twice then stops).

HTML

<div id="container"></div>
<br/><br/><br/><br/>
<div id="xx">Not Fired..."</div>

JavaScript:

    var cnt = 0;
    (function loadWidget() {
        var widgetObj = document.createElement("object");
        widgetObj.data = ("http://13.75.145.9/widgets/dial.html")                                  // location of widget
        var tt = document.getElementById("container");
        tt.appendChild(widgetObj);
        widgetObj.addEventListener("load", widgetLoaded, false);
    })();

    function widgetLoaded(e) {
        cnt = cnt + 1;
        document.getElementById("xx").innerText = "fired x" + cnt;
    //any manipulation of style is OK, its only the position: absolute that causes re-firing
        e.currentTarget.style = "cursor: move; text-decoration: overline";
        e.currentTarget.style.setProperty("position", "relative");
    // Uncomment out the line below in Chrome and the event will continuously fire, but only once in othe browsers
        e.currentTarget.style = "position: absolute; left: 50px";
    }

Infinite loop

I'm assuming this is a Chrome bug, and although I can work around it by checking how many times the object has been loaded and exit the load event early, there is a performance penalty because it looks like the entire object is reloaded each time (global JavaScript in the object is re-run) and when loading a couple of widgets as objects the browser significantly slows down impacting the end user experience.

No matter what I try I can't seem to avoid the multiple re-loads happening. Has anyone else seen this bug and knows how to avoid the re-loading?

On a related note, Chrome will render and display the object then move it to its correct position which flickers the screen, while other browsers will render the widget at its final location (after the load javascript has been run) which is a nicer experience and I can't find a way to stop Chrome rendering twice.

[Update December '18] - the workaround outlined in the answers below no longer work with the latest version of Chrome (71.0.3578.80) and Chrome is double loading HTML objects and double firing the loaded events. See this Chromium bug post for more info: Chrome bug with HTML Objects

Besetting answered 25/4, 2018 at 9:51 Comment(0)
A
5

Not sure about reasons for such behavior in Chrome. However, a workaround seems to be a changing container's style instead of object's style - see fiddle

function widgetLoaded(e) {        
    const target = e.currentTarget;        
    target.parentElement.style = "position: absolute; left: 50px;";
 }

Also after some investigation, I have found that issue probably caused by changing display from inline to block - see fiddle.

Adalia answered 27/4, 2018 at 20:49 Comment(10)
The change to display block does fix the issue for my app. Your other option of changing the container style is also possible by encapsulating the object in a DIV however for my app the display block is more appropriate, thanks.Besetting
@deandob, it may be a bug a cross browser stuff which works differently. But there is a much simpler workaround, see the answer I postedHeadreach
I still can't solve the last part of this problem - where chrome will render the object twice (even with the load event only firing once). First time chrome renders the object at position 0,0 then in the event it moves it to the correct place (left:50px) and you see the object flickering over the screen. It is obvious in the fiddle and makes the chrome experience in my app visually messy. The other browsers will render the object cleanly once the load event is completed. I have tried a couple of things (eg. move container off the screen) but nothing seems to change this behavior. Any ideas?Besetting
@Besetting as an option you can use some CSS tricks - make your object "invisible" and show only after load - jsfiddle.net/xLzo25jp/8Adalia
@mykhailo, I have up to 50 objects to load on the screen so doing CSS transitions is likely going to slow down the page loading (fast load is important). But if I set width:0 before the object is loaded then adjust width after load, Chrome now renders gracefully. Edge is still a problem but I'll try a number of similar tips to get it working gracefully as well (these small browser behavior differences get annoying...)Besetting
@Besetting transition is fully optional in my example, feel free to skip it. Glad to hear that you have overcome your issues. And I totally agree that this issue with load is painful. You can try to submit this issue to chromium issues trackerAdalia
Got this working nicely for both Edge and Chrome by using opacity 0 on the parent div before loading the widgets, then opacity 1 once all the load events completed. Looks nice and performs well - thanks for the tips.Besetting
This problem has come back with the latest version of Chrome, previously the workaround to change the object to display: block avoided the double event for object load, its not working on now on Chrome 71.0.3578.80 (the double event call bug is back). See this fiddle that puts the latest Chrome object call looping but it only runs once with other browsers. jsfiddle.net/xLzo25jp/5Besetting
If anyone has an idea about how to workaround this, please post here. I'll lodge it with Google as a bug.Besetting
A workaround that is acceptable for my application to prevent the double load is to replace the object tag with an iframe tag - they are very similar, work the same way (replace .data with .scr) and from our testing have no other side effect.Besetting

© 2022 - 2024 — McMap. All rights reserved.