|
I have been having this kind of hair tearing problem with Internet Explorer
6 in the last few days while trying to implement drag and drop within the AJAX
framework of Ruby On Rails. The problem is extremely frustrating to track down
as it works perfectly with Firefox (a sign of the time, I suppose, IE used to
be the benchmark for sane rendering, but alas no more !). Hopefully by
detailing it here, no one else will have to go through the same pain I did.
I should point out here that most advertised features work perfectly in
both Internet Explorer and Firefox. However, it was a combination of what I
did which caused problems in IE. So if you ever get this problem where
Internet Explorer throws out this Javascript error "Unspecified error" each
time you attempt to move a drag-able item over potential drop sites, then read
on.
Ruby On Rails comes integrated with a pretty cool Javascript client library
called Scriptaculous, which takes away
the pain of cross browser incompatibilities (supposedly, but as I will show
here, even this library has its limits when it comes to browser
idiosyncrasies). Scriptaculous provides
AJAX support, drag and drop,
auto-complete, and many other cool features out of the box. I had no problem
implementing the basic drag and drop, which worked fine in both Firefox and
Internet Explorer. However, I ran into the above mentioned error where
Internet Explorer will consistently throw out streams of Javascript
"Unspecified error" once a drop has been made. The error itself is of no help
as it gives you no clues as to what the problem is. What is it which has
completely messed up the DOM in such a way that once the first drop is made,
no other items can be dragged around without causing errors ? The Javascript
error happens consistently on a block of code in the dragdrop.js file
at line 1589, column 7, which is highlighted red
below.
var Enumerable = {
each: function(iterator) {
var index = 0;
try {
this._each(function(value) {
try {
iterator(value, index++);
} catch (e) {
if (e != $continue) throw e;
}
});
} catch (e) {
if (e != $break) throw e;
}
},
I tried out the Scriptaculous demo shopping cart
on Internet Explorer, which works perfectly. This tells me Internet
Explorer is not the problem, or indeed the basic boiler plate drag and drop
code (just a process of elimination). Well, back to my code. It must be
something in my code that causes this. The basic code must work as I am able
to drop the draggable item once. So, it must be something to do with the
sequence of events, rather than the drag and drop technology itself. I viewed
the html before and after the drag and drop action, looks ok. Then I viewed
the list of Droppables objects using the JScript debugger, this looked
OK too.
Google was of no help. Not sure if it is because the subject is relatively
new (Ruby on Rails, AJAX, Scriptaculous etc.). Whatever I could find led me to
try out these desperate measures:
- download the latest version of Scriptaculous instead of using the one
packaged with Rails
- deploy an application called
Browser Object
Helper daemon, which allows me to look at all the third party extensions
loaded into IE on start up, as these BOH's have been known to cause problems
with IE crashing with "Unspecified error"
- re-engineer my pages so that the different fragments get generated
together instead of via cascaded Javascript hooks on the :onComplete event
None of the above solutions helped !! Where is Sherlock when you need him ?
Then, on the third day (what is it about the third day ? I always seem to
have more luck on the third day !), something dawned on me. I quickly checked
out the list of drop sites again in the JScript debugger, and sure enough, the
error always happened on the second drop site in the list. A quick drill down
gave me an insight into my problem, in that the second drop site has the
same name as the first drop site. How is this possible ? pages are
generated on the fly, and all the drop sites are guaranteed to have unique
id's within the page. Looking through the code again told me the
problem, which is to do with Rails's partial rendering mechanism. Rails has a
very good built in AJAX engine, which allows you to refresh fragments of the
page without regenerating the whole page (this is the technology used
extensively at Google Maps). It is
this partial rendering which is the root of all problems. Normally, when a
page is reloaded, the whole list of drop sites, which is built up from the
initial rendering, is started from scratch. In fact, this should work
perfectly too, normally, if you do not re-generate the drop sites within the
page as part of partial rendering. However, if these drop sites are
re-generated (as mine is), then this is when IE behaves differently to
Firefox.
Firefox looks like it did the right thing (or maybe not, depending on your
point of view), and still honours calls to the DOM element associated with the
defunct drop site, specifically the cumulativeOffset() call in dragdrop.js,
which traverses up the DOM in order to calculate the overlap between the
dragged item and the drop site. It could be because Firefox looks up the DOM
element by name and resolves it to the newly created element automatically
(cool or what ?).
However, Internet Explorer goes completely crazy on this (or maybe it
should, again depending on your point of view) and throws out these JScript
errors about the dead drop site still sitting happily in the cached list of
Droppables. This list is created by the drag and drop technology, and
because we are not reloading the page, is never cleared out properly between
AJAX calls.
The solution, once known looks so simple, is to place this Javascript call
into the page fragment which is re-built on each AJAX call (but only if you
intend to re-generate the drop sites):
<script>
if (document.all) { Droppables.drops = [] }
</script>
Go, go, gadgets, go !!The footnote is, however, even though Firefox is more
forgiving in this instance (I mean it does the right thing in terms of
intended design), in the long run, if your partial rendering is more
intensive, it is probably a good idea to clear out the drop sites regardless
of the browser to make it more memory efficient and also quicker to iterate
through the list of possible drop sites each time an item is dragged around on
the screen.
Also, the moral of the story is, Internet Explorer absolutely detests
having different DOM elements with the same identifier. Firefox seems to do
something internally to cope with this rather impressively. As a client side
developer, I know which one I'd rather use. Alas, the majority out there do
not write web pages for a living. Also, if technical superiority counts, we'd
all be using Betamax tapes, right ? |
Home
Contact us
|