Opened 10 years ago

Closed 10 years ago

Last modified 7 years ago

#4918 closed bug (notabug)

undefined error because of UI's droppable

Reported by: nicolas Owned by:
Priority: critical Milestone:
Component: ui.core Version: 1.7.2
Keywords: Cc:
Blocked by: Blocking:

Description

Hi,

we are currently having somewhat of a big issue when using UI's draggable and droppable features.

We have DIV's on the page that are .resizable() and .draggable(). This has always worked fine (we are able to move and resize all DIV's on the page).

Lately, we have added to some of those DIV's the .droppable() feature. Since then, bugs happen.

At initial load, everything is fine. It is possible to move and resize all DIV's, and those having the droppable() property are effectively used as drop-zones (in addition to being resizable and draggable).

After a postback, in which we alter the control tree and do some heavy AJAX duty, when trying to move a DIV that has the droppable() property, we get an unspecified error on the following line of code:

var G=this[0].getBoundingClientRect()

That is located in jquery-1.3.2.js, under the Sizzle CSS Selector Engine. We tried going back to jquery-1.6.2.js, and in that case, we get the unspecified error on another line:

offsetParent = elem.offsetParent

The error only happens after some AJAX is done, and only when trying to drag a DIV that has the droppable() property set. Trying to move any other DIV will not cause any error. Pushing F5 after we got the error, and then after trying to move a DIV that is set as droppable(), will not cause any error until heavy AJAX happens again.

There is something I have noticed, not sure if this can help, but this proves something is wrong somewhere in the CSS. When doing the AJAX thing that then causes the error to happen, I notice a CSS change on the DIV's that are set as droppable. The difference appears to be some transparency issue. See an example here:

before AJAX: http://img8.imageshack.us/i/beforelg.png/
after AJAX: http://img42.imageshack.us/i/afterd.png/

Look at the right and bottom sides of the chart. Please note though, that this also happens when the droppable() is not set (thus no error happens at all), so it may totally unrelated. Also, this is not very important and does not require an immediate fix - I'm just showing this in case it may has something to do with our issue.

I have done some research and found that other people have similar problems, although it did not help us find a solution:

http://weblogs.asp.net/rajbk/archive/2006/11/29/ie-6-7-unspecified-error-when-accessing-offsetparent-javascript.aspx http://www.nabble.com/jQuery-offsetParent---using-with-drag-drop-UI-problem-in-IE7-td21871703s27240.html

We are using IE8 (same behavior with IE8 and IE7 compatibility view) with Vista x64. Unfortunately, the application is really complex and AJAX heavy, so it is near to impossible to create a sample project reproducing the issue. It also won't run in Firefox or anything else than IE (8, for that matter).

Any help is appreciated.

Thanks,
Nicolas

Change History (7)

comment:1 in reply to:  description Changed 10 years ago by nicolas

Hi,

this was fixed thanks to using this code, apparently redefining the offset function to make it work under IE:


// 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;
};

function IESafeOffsetParent(elem) {
    try {
        return elem.offsetParent;
    }
    catch (e) {
        return document.body;
    }
}

Any chance you can fix that in a future release of jQuery so that we can get rid of that fix?

Thanks

comment:2 Changed 10 years ago by Scott González

Resolution: invalid
Status: newclosed

Bugs in .offset() belong in jQuery's bug tracker.

comment:3 Changed 10 years ago by Sensor

what is this fix? HELP!!!

comment:4 in reply to:  3 ; Changed 10 years ago by Sensor

Replying to Sensor:

Could you please tell me how to patch this this fix? HELP!!!

comment:5 in reply to:  4 Changed 10 years ago by Sensor

Replying to Sensor:

Replying to Sensor:

Could you please tell me how to patch this fix? HELP!!!

comment:6 Changed 10 years ago by ckosti

I have the same issue. An ASP.NET AJAX call replaces #dropContainer, but $.ui.ddmanager.droppables.default continues to hold on to the old instances of #dropContainer. So after two calls back to the server, I end up with three instances of #dropContainer in $.ui.ddmanager.droppables.default, only one of which actually exists in the document tree.

Then when a drag starts, prepareOffsets() gets called, which results in getBoundingClientRect() being called against elements that have no parent element. In IE, this causes an error.

It seems unlikely to me that $.ui.ddmanager was intended to hold onto dead elements. In that case, I think this indicates that there are bugs in both libraries. The corresponding ticket for JQuery's .offset() issue is here for anyone who is interested: http://dev.jquery.com/ticket/4996

comment:7 Changed 7 years ago by Scott González

Milestone: TBD

Milestone TBD deleted

Note: See TracTickets for help on using tickets.