jQuery draggable shows helper in wrong place after page scrolled

88,807

Solution 1

This might be a related bug report, it's been around for quite a while: http://bugs.jqueryui.com/ticket/3740

It seems to happen on every browser I tested (Chrome, FF4, IE9). There are a few ways you can work around this issue:

1. Use position:absolute; in your css. Absolutely positioned elements don't seem to be affected.

2. Make sure the parent element (event if it's the body) has overflow:auto; set. My test showed that this solution fixes the position, but it disables the autoscroll functionality. You can still scroll using the mousewheel or the arrow keys.

3. Apply the fix suggested in the above bug report manually and test thouroughly if it causes other problems.

4. Wait for an official fix. It's scheduled to jQuery UI 1.9, although it has been postponed a few times in the past.

5. If you're confident that it happens on every browser, you can put these hacks into the affected draggables' events to correct the calculations. It's a lot of different browsers to test though, so it should only be used as a last resort:

$('.drag').draggable({
   scroll:true,
   start: function(){
      $(this).data("startingScrollTop",$(this).parent().scrollTop());
   },
   drag: function(event,ui){
      var st = parseInt($(this).data("startingScrollTop"));
      ui.position.top -= $(this).parent().scrollTop() - st;
   }
});

Solution 2

This solution works without adjusting the positioning of anything, you just clone the element and make it absolutely positioned.

$(".sidebar_container").sortable({
  ..
  helper: function(event, ui){
    var $clone =  $(ui).clone();
    $clone .css('position','absolute');
    return $clone.get(0);
  },
  ...
});

The helper can be a function which needs to return the DOM element to drag with.

Solution 3

This worked for me:

start: function (event, ui) {
   $(this).data("startingScrollTop",window.pageYOffset);
},
drag: function(event,ui){
   var st = parseInt($(this).data("startingScrollTop"));
   ui.position.top -= st;
},

Solution 4

Sorry for writing another answer. As none of the solutions in the above answer could be used by me I did a lot of Googling and made many frustrating minor edits before finding another reasonable solution.

This issue seems to occur whenever any of the parent elements have position set to 'relative'. I had to reshuffle my markup and alter my CSS but by removing this property from all parents, I was able to get .sortable() working properly in all browsers.

Solution 5

It looks like this bug comes around very often, and every time there is a different solution. None of the above, or anything else I found on the internet worked. I'm using jQuery 1.9.1 and Jquery UI 1.10.3. This is how I fixed it:

$(".dragme").draggable({
  appendTo: "body",
  helper: "clone",
  scroll: false,
  cursorAt: {left: 5, top: 5},
  start: function(event, ui) {
    if(! $.browser.chrome) ui.position.top -= $(window).scrollTop();
  },
  drag: function(event, ui) {
    if(! $.browser.chrome) ui.position.top -= $(window).scrollTop();
  }
});

Works in FF, IE, Chrome, I've not yet tested it in other browsers.

Share:
88,807

Related videos on Youtube

Alex
Author by

Alex

I'm a front-end & javascript developer in London.

Updated on July 05, 2022

Comments

  • Alex
    Alex almost 2 years

    I'm using jQuery draggable and droppable for a work-planning system I'm developing. Users drag jobs to a different day or user, and then data is updated using an ajax call.

    Everything works fine, except when I scroll down the main page (Jobs appear on a large week planner that exceeds the bottom of my browser window). If I try and drag a draggable element here, the element appears above my mouse cursor the same amount of pixels as I've scrolled down.. The hover state still works fine and the functionality is bang on but it doesn't look right.

    I'm using jQuery 1.6.0 and jQuery UI 1.8.12.

    I'm sure there's a offset function I need to add but I don't know where to apply it, or if there's a better way. Here's my .draggable() initialisation code:

    $('.job').draggable({
      zIndex: 20,
      revert: 'invalid',
      helper: 'original',
      distance: 30,
      refreshPositions: true,
    });
    

    Any idea what I can do to fix this?

    • jimy
      jimy about 13 years
      can you provide some working demo
    • Alex
      Alex about 13 years
      @jimy it's all dynamic and very secure so I'd have to write a whole new example; I will do if nobody has a quick answer ASAP.
    • DarthJDG
      DarthJDG about 13 years
      Can you post all css properties your draggable has or inherits?
    • Patrick
      Patrick over 10 years
      Per my answer far below, this appears to be finally fixed
  • Alex
    Alex about 13 years
    That's great, thank you! (Settings overflow:auto fixed it immediately. I applied the style to the individual table cells.
  • Altreus
    Altreus almost 13 years
    I discovered the bug also happens if your source draggable object is a child of a position: fixed element. The only thing that worked for me was to move the clone out of the fixed element -- start: function(event,ui) { ui.helper.appendTo($('body')); } -- and apply the patch in the bug report. hth
  • digitalPBK
    digitalPBK almost 12 years
    jsfiddle.net/a2hzt/5 overflow-y: scroll on the html element also creates this problem on firefox (chrome works), just scroll down and try dragging.
  • Iain Collins
    Iain Collins over 11 years
    +1 Thanks very much, this works for me with sortable (I was about to try something similar but less elegant). You have a small typo with $j though! :)
  • mirelon
    mirelon about 11 years
    This works, but when you scroll while dragging, it still shifts the y position. The DarthJDG's solution number 5 works also when scrolling while dragging.
  • wojtiku
    wojtiku about 11 years
    The same for me here. Any position: relative; in any parent causes this to happen.
  • wojtiku
    wojtiku about 11 years
    Answer by @Josh 'Bambi' Bambrick also seems to do the trick. So removing position: relative; from all the parents is also good solution.
  • Calciphus
    Calciphus almost 11 years
    The last resort option ALMOST worked for me, except that the divs I was scrolling weren't in the parent layer (they were several up), so I defined them by the selector. Also, for some reason your code has -= in the ui.position setter, rather than +=, which is what fixed my situation. In case anyone else gets stuck on this, try (in the drag function): drag: function(event,ui){ var st = parseInt($(this).data("startingScrollTop")); ui.position.top += $("#parent-div-selector").scrollTop() - st; }
  • ProblemsOfSumit
    ProblemsOfSumit almost 11 years
    For me: drag doesn't work at all with this and returns errors: TypeError: this.offsetParent[0] is undefined
  • ProblemsOfSumit
    ProblemsOfSumit almost 11 years
    this is driving me insane. I got horizontal scrolling (simple slider with draggable elements inside the slides) and their positioning is crazy. No solution worked so far :-/
  • ProblemsOfSumit
    ProblemsOfSumit almost 11 years
    ok i figured out my problem: the solution was to delete the "containment" option! I searched for hours!
  • Bob Stein
    Bob Stein almost 11 years
    It's ba-a-ack, for helper: "clone". bugs.jqueryui.com/ticket/9315 Level blocker, a notch above major. tj.vantoll says "6 draggable fixes that landed in 1.10.3 might be suspect." Simplest example yet: jsfiddle.net/7AxXE
  • Bob Stein
    Bob Stein almost 11 years
    Confirmed, this bug is in jQuery UI 1.10.3 but not 1.10.2
  • con
    con over 10 years
    totally aggree! For me, it was just an inline style in the body with position: relative; which had to be removed.. parent elements between the draggable and the body seems not to make problemes here..
  • He Nrik
    He Nrik over 10 years
    For some reason, the overflow or position didn't work for me. But changing in the source code did. But rolling back to 1.10.2 felt like a more proper solution in our project.
  • Scott Alexander
    Scott Alexander over 10 years
    I'm using 1.10.4 and the bug is still there, used that link though and all is working well.
  • Patrick
    Patrick over 10 years
    @ScottAlexander The fix may have gotten attached to a different ticket than I thought. I've edited my answer based on that. Thanks!
  • lhan
    lhan about 10 years
    Looks like the problem also exists in jQuery UI 1.10.4. I'll just stick to 1.10.2 for now!
  • John Smith
    John Smith almost 10 years
    Thanks! this is the only thing that worked for me. (I'm not sure I understand the problem.. my problem is that dragging, dragging scrolling work fine when the drag starts with the scrollbar at the top. If the scroll bar starts lower then I get an offset issue)
  • Mohammed Joraid
    Mohammed Joraid almost 10 years
    I think it's ui.helper not only ui
  • Philidor
    Philidor over 9 years
    "1.11.0" bug still here.
  • Philidor
    Philidor over 9 years
    fix my problem, "1.11.0"
  • c.dunlap
    c.dunlap over 9 years
    this worked for me, except I had to use ui.offset.top instead of ui.position.top
  • BGBRUNO
    BGBRUNO over 9 years
    Thank you help me with Sortable
  • Victor
    Victor over 9 years
    looks like the bug still exists in "1.11.2" as well
  • thanh
    thanh over 9 years
    My problem that i have to work on long list table have scroll and draggable items in it . This bug still in "1.11.2". Any suggestion for this. I have tried all solution i founded but still can't fix it. Here is the jsfiddle
  • Lode
    Lode over 9 years
    For me the bug is fixed when using 1.11.2 (I came from 1.10.4).
  • Cesar Bielich
    Cesar Bielich about 9 years
    racked my brains on this exact issue and overflow:auto; totally worked for me, thanks man.
  • Fabien Quatravaux
    Fabien Quatravaux about 9 years
    For me, the bug was not here with 1.10.4 but it reappeared with version 1.11.2. overflow:auto or overflow:hidden are good workarounds. I don't know how to reopen the bug for the jQueryUI team.
  • andrea.spot.
    andrea.spot. about 9 years
    Point 1) is quite misleading. Actually it's not about absolutely positioning elements, but being sure that their container have position (absolute or relative) specified. I fixed this problem setting position:relative on the container, because helper element was previously positioned absolutely to an outer container.
  • manu
    manu almost 9 years
    That's an funny solution, but It will only work on browsers that do have the bug (Chrome). Browsers that don't have the bug will now have it but inverted :)
  • Shawn V
    Shawn V almost 9 years
    Thank you for this answer, I had everything but the overflow: auto and this solution fixed my errors
  • Dominic
    Dominic over 8 years
    omg that was it thanks, garrr why are people not using Dragula in this day and age - thanks!
  • Dominic
    Dominic over 8 years
    After up-voting this as one of the lesser hacky solutions I realised the problem for me was that a parent had position: relative as @Josh Bambrick discovered
  • Barry Chapman
    Barry Chapman almost 8 years
    perfect fix when using position: relative; is absolutely required. +1
  • gdibble
    gdibble over 7 years
    position: relative may have worked if you moved it to a higher-level container element. I know it doesn't help now, but just for reference and maybe for a future troubled developer.
  • Brett Gregson
    Brett Gregson over 6 years
    This is the only answer that works for me, and it's the simplest to implement. Great solution
  • wjk2a1
    wjk2a1 over 6 years
    Thank you so much! Parent of parent having position:relative caused it for me
  • ripper17
    ripper17 about 6 years
    Note: some JS-Parsers might complain about "missing radix" when using this solution. To fix, replace var st = parseInt($(this).data("startingScrollTop")); with var st = parseInt($(this).data("startingScrollTop"), 10); (i.e. provide the numeral system to be used). 10 is the default, but some parsers might require this to be present nontheless (e.g. webpack)
  • Vidmantas Norkus
    Vidmantas Norkus over 5 years
    following add will add better feeling when dragging $(ui).css({ 'opacity': '0.1' }); (add after clone)
  • Istiaque Ahmed
    Istiaque Ahmed over 5 years
    @DartJDG, may I ask you to take a look at a draggable related question here : stackoverflow.com/questions/54498364/…
  • Konstantin
    Konstantin almost 5 years
    Wow! I've spent a whole day trying to find a workaround, but a simple overflow: auto; did the trick! The biggest thank to you ever :D
  • tsumnia
    tsumnia over 2 years
    Chiming in to say this solved my issues! I'm using the js-parsons library, which has not been updated in years, so it still uses jQuery 1.7.2. Removing the position: relative from one of its parents fixed the issue.