Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

<object> tag doesn't refresh when its data attribute is changed in Chrome [duplicate]

I have an <object> tag on a web page, whose data attribute is changed programmatically in JS (jQuery, specifically). The data tag always points to a SVG image.

In Firefox, when the data tag is changed, the new SVG loads and all the proper events fire. In Chrome, this doesn't occur until I click on the SVG canvas -- once that happens, the new SVG displays and its associated events all fire.

Why is this? How can I force Chrome to refresh the <object> when I change its data attribute?

like image 995
Tom Corelis Avatar asked Apr 28 '12 19:04

Tom Corelis


3 Answers

Well, I was really bored tonight and I wanted to do something that wasn't schoolwork, so I dug through a lot of specs and forums for you.

The HTML4 spec doesn't seem to have any mention of SVG, so there's a dead end. The HTML5 Spec Working Draft tells us that we can use data to invoke plugins and load content. The HTML5 Spec Editor's Draft does mention SVG, telling us that SVG falls under the category of embedded content.

Because the Editor's Draft adds additional detail to the <object> element as defined in the Working Draft, we could say that the behavior of loading <object> elements is not an accepted standard. (Somebody please correct me if I'm wrong.)

Anyway, in the <object> specification, aside from all the usual technical jargon about how the browser should interpret the object by MIME-type etc... We find the part that's relevant to this question:

4.6: If the load failed (e.g. there was an HTTP 404 error, there was a DNS error), fire a simple event named error at the element, then jump to the last step in the overall set of steps (fallback).

...

10.: Once the resource is completely loaded, queue a task to fire a simple event named load at the element.

(Simple events merely mean that the events do not bubble (so we can't listen for it in any parent elements) and are not cancelable, and use the Event interface)

So, looking at this, I figured that if I select the <object> element off the DOM, it should have an onload and onerror event, if not object.addEventListener. If you look at the Mozilla Developer Network docs for SVG and <object>, much of the JavaScript documentation is incomplete. Bummer.

Just goofing around with JSFiddle and the Chrome Dev Tools and Firefox Web Console, I found that they both supported onload and onerror, or so I thought.

Results of testing

Google Chrome (18.0.1025.165) and Firefox (12.0)

Supports:

  • addEventListener('load', function(){})
  • obj.onload = function(){};

Does not support (events don't seem to fire):

  • addEventListener('error', function(){})
  • obj.onerror = function(){}

As you can see from the fiddle, in Chrome using the load event causes infinite loops. It is not supposed to do this (according to the editor's draft):

The above algorithm is independent of CSS properties (including 'display', 'overflow', and 'visibility'). For example, it runs even if the element is hidden with a 'display:none' CSS style, and does not run again if the element's visibility changes.

It looks like somebody already filed a bug, so if you would go and confirm the bug it would help the Chrome Developers Team.

TL;DR

The behavior for loading objects is not an accepted standard yet, but you can go verify a bug in the Chromium project. You could try doing as @Hello71 suggested and try removing the element from the DOM and re-adding it, but I couldn't get it to work.

like image 110
Stanley Stuart Avatar answered Oct 17 '22 13:10

Stanley Stuart


Actually, I got exactly the same issue. Have a look at the http://jsfiddle.net/unesJ/, I solved it with the following code:

The html:

<object id="graph" data="image1.svg" type="image/svg+xml"></object>

The javascript:

var new_url = 'image2.svg';
$('#graph').attr('data', new_url);
$('#graph').load(new_url);

It work for me on

  • Chrome 24.0.1312.52 m
  • Firefox 17.0.1
like image 7
Stéphane Avatar answered Oct 17 '22 12:10

Stéphane


I have tried quite a few things. Unfortunately I've had to resort to doing the following:

setTimeout(function(){
  $('body').trigger('click');
}, 40);

No, I don't really have a better solution, but it gets the job done.

like image 2
ProLoser Avatar answered Oct 17 '22 14:10

ProLoser