I\'m using jQuery UI\'s draggable and droppable libraries in a simple ASP.NET proof of concept application. This page uses the ASP.NET AJAX UpdatePanel to do partial page up
This isn't just a jQuery error. I encountered it using ExtJS 4.0.2a on IE8. It seems that IE will almost always stumble on element.getBoundingClientRect()
if the element has been replaced in the DOM. Your try/catch hack is pretty much the only way to get around this. I guess the actual solution would be to eventually drop IE < 9 support.
Relevent ExtJS v4.0.2a Source Code (lines 11861-11869):
...
if(el != bd){
hasAbsolute = fly(el).isStyle("position", "absolute");
if (el.getBoundingClientRect) {
b = el.getBoundingClientRect();
scroll = fly(document).getScroll();
ret = [Math.round(b.left + scroll.left), Math.round(b.top + scroll.top)];
} else {
...
With a try/catch fix:
...
if(el != bd){
hasAbsolute = fly(el).isStyle("position", "absolute");
if (el.getBoundingClientRect) {
try {
b = el.getBoundingClientRect();
scroll = fly(document).getScroll();
ret = [Math.round(b.left + scroll.left), Math.round(b.top + scroll.top)];
} catch(e) {
ret = [0,0];
}
} else {
...
My version is:
Add function:
function getOffsetSum(elem) {
var top = 0, left = 0
while (elem) {
top = top + parseInt(elem.offsetTop)
left = left + parseInt(elem.offsetLeft)
try {
elem = elem.offsetParent
}
catch (e) {
return { top: top, left: left }
}
}
return { top: top, left: left }
};
replace
var box = this[0].getBoundingClientRect()
with
var box = getOffsetSum(this[0])
PS: jquery-1.3.2.
i tried the following workaround for the getBoundingClientRect() unspecified error whilst drag n drop, and it works fine.
in the jquery.1.4.2.js (i.e base jquery file, where the error is thrown exactly)
replace the elem.getBoundingClientRect() function call in js file
//the line which throws the unspecified error
var box = elem.getBoundingClientRect(),
with this..
var box = null;
try
{
box = elem.getBoundingClientRect();
}
catch(e)
{
box = { top : elem.offsetTop, left : elem.offsetLeft } ;
}
This solves the issue and drag n drop will work quitely even after post back through update panel
Regards
Raghu
@arilanto - I include this script after my jquery scripts. Performance wise, it's not the best solution, but it is a quick easy work around.
function IESafeOffsetParent(elem)
{
try
{
return elem.offsetParent;
}
catch(e)
{
return document.body;
}
}
// The Offset Method
// Originally By Brandon Aaron, part of the Dimension Plugin
// http://jquery.com/plugins/project/dimensions
jQuery.fn.offset = function() {
/// <summary>
/// Gets the current offset of the first matched element relative to the viewport.
/// </summary>
/// <returns type="Object">An object with two Integer properties, 'top' and 'left'.</returns>
var left = 0, top = 0, elem = this[0], results;
if ( elem ) with ( jQuery.browser ) {
var parent = elem.parentNode,
offsetChild = elem,
offsetParent = IESafeOffsetParent(elem),
doc = elem.ownerDocument,
safari2 = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
css = jQuery.curCSS,
fixed = css(elem, "position") == "fixed";
// Use getBoundingClientRect if available
if (false && elem.getBoundingClientRect) {
var box = elem.getBoundingClientRect();
// Add the document scroll offsets
add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
// IE adds the HTML element's border, by default it is medium which is 2px
// IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
// IE 7 standards mode, the border is always 2px
// This border/offset is typically represented by the clientLeft and clientTop properties
// However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
// Therefore this method will be off by 2px in IE while in quirksmode
add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
// Otherwise loop through the offsetParents and parentNodes
} else {
// Initial element offsets
add( elem.offsetLeft, elem.offsetTop );
// Get parent offsets
while ( offsetParent ) {
// Add offsetParent offsets
add( offsetParent.offsetLeft, offsetParent.offsetTop );
// Mozilla and Safari > 2 does not include the border on offset parents
// However Mozilla adds the border for table or table cells
if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
border( offsetParent );
// Add the document scroll offsets if position is fixed on any offsetParent
if ( !fixed && css(offsetParent, "position") == "fixed" )
fixed = true;
// Set offsetChild to previous offsetParent unless it is the body element
offsetChild = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
// Get next offsetParent
offsetParent = offsetParent.offsetParent;
}
// Get parent scroll offsets
while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
// Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
if ( !/^inline|table.*$/i.test(css(parent, "display")) )
// Subtract parent scroll offsets
add( -parent.scrollLeft, -parent.scrollTop );
// Mozilla does not add the border for a parent that has overflow != visible
if ( mozilla && css(parent, "overflow") != "visible" )
border( parent );
// Get next parent
parent = parent.parentNode;
}
// Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
// Mozilla doubles body offsets with a non-absolutely positioned offsetChild
if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) ||
(mozilla && css(offsetChild, "position") != "absolute") )
add( -doc.body.offsetLeft, -doc.body.offsetTop );
// Add the document scroll offsets if position is fixed
if ( fixed )
add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
}
// Return an object with top and left properties
results = { top: top, left: left };
}
function border(elem) {
/// <summary>
/// This method is internal.
/// </summary>
/// <private />
add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
}
function add(l, t) {
/// <summary>
/// This method is internal.
/// </summary>
/// <private />
left += parseInt(l, 10) || 0;
top += parseInt(t, 10) || 0;
}
return results;
};
If you would like to fix the minified/compressed .js file for jQuery version 1.4.2, replace:
var d=b.getBoundingClientRect(),
with
var d = null;
try { d = b.getBoundingClientRect(); }
catch(e) { d = { top : b.offsetTop, left : b.offsetLeft } ; }
(note that there is no comma after the closing brace now)
@Raghu
Thanks for this bit of code! I was having the same problem in IE and this fixed it.
var box = null;
try {
box = elem.getBoundingClientRect();
} catch(e) {
box = {
top : elem.offsetTop,
left : elem.offsetLeft
};
}