Expanding a collapsible set should scroll you to the top of it's contents #2167

Closed
InvisibleBacon opened this Issue Jul 28, 2011 · 26 comments
@InvisibleBacon

If you have more than a page's height worth of contents in your first collapsible container, and you scroll down to the second set to expand, the browser's scroll position does not change, leaving you in the middle of the second container's contents. I fixed this on our site by scrolling to the top of the clicked header if it is off the top of the page after an expansion. Here's the code I use:

$("div.ui-collapsible-set").live("expand", function(e) {
    var top = $(e.target).offset().top;
        if ($(window).scrollTop() > top)
            $(window).scrollTop(top);
});
@LockyBoy

Really useful bit of code, thanks for that

@toddparker

This seems like a good idea. Mind creating a pull request?

@johnbender johnbender was assigned Aug 7, 2011
@ricksuggs

Cover the case that there is a previously expanded collapsible whose collapsing will cause the position of the subsequently expanding collapsible to change before adjusting the scroll position:

var lastExpanded;
$('div.ui-collapsible-contain').live('expand', function() {
    var $expandable = $(this);
    // wait until the lastExpanded is collapsed
    var intervalId = setInterval(function() {
        if (lastExpanded && lastExpanded.has( ".ui-collapsible-heading-collapsed" )) {
            var expandableTop = $expandable.offset().top,
            $window = $(window),
            targetPos = expandableTop - $window.scrollTop() + $expandable.height();
            if (targetPos > $window.height() || expandableTop < $window.scrollTop()) {
                $.mobile.silentScroll(expandableTop);
            }
            clearInterval(intervalId);
            lastExpanded = $expandable;
        } else {
            lastExpanded = $expandable;
        }
    }, 200);
});
@CaDs

You just made my day!
Thanks a lot for the code

@adrianpillinger

The current version of jquery-mobile (1.0) needs a slightly different class in the initial selector.

        var lastExpanded;
        $('div.ui-collapsible').live('expand', function() {
            var $expandable = $(this);
            // wait until the lastExpanded is collapsed
            var intervalId = setInterval(function() {
                if (lastExpanded && lastExpanded.has( ".ui-collapsible-heading-collapsed" )) {
                    var expandableTop = $expandable.offset().top,
                    $window = $(window),
                    targetPos = expandableTop - $window.scrollTop() + $expandable.height();
                    if (targetPos > $window.height() || expandableTop < $window.scrollTop()) {
                        $.mobile.silentScroll(expandableTop);
                    }
                    clearInterval(intervalId);
                    lastExpanded = $expandable;
                } else {
                    lastExpanded = $expandable;
                }
            }, 200);
        });

Has this code been added to jQuery mobile, or do you want a pull request still ?

@toddparker

We did a bit of work on this but ran into some issues on edge cases. If this is working well for you and works on our target browsers, I'd love to see a pull request, sure.

@adrianpillinger

I've not done any extensive testing yet with this, but would be happy to test it and attempt to tweak to work with the browsers I have access to...

iOS 5
Android (not sure what version off hand)
Current latest version of
Safari on Mac OS X
Firefox on Mac OS X
Firefox on windows
Chrome on windows
Chrome on Mac OS X

I'll have a play and if I get something working with the browsers I have access to I'll issue a pull request for someone to complete testing on other browsers.

Cheers
Adrian

@toddparker

@adrianpillinger - We can test this on our side too. Do you have a demo page or PR?

@adrianpillinger

Sorry for the slow reply - busy at work and home...I am working on a pull request.

@adrianpillinger adrianpillinger added a commit to adrianpillinger/jquery-mobile that referenced this issue Jan 31, 2012
@adrianpillinger adrianpillinger #2167 Implementing auto-scroll to top of collapsible sections on expand.
Adds an event listener to enable auto scroll to the top of a
collapsible section when it is expanded. Credit is due to @ricksuggs
for the implementation of the scroll code.
2b7eec4
@adrianpillinger

Pull request made.

@sblenkhorne

That's perfect! Thanks so much for sharing this. So easy to use. Copy and pasted in my code it worked without a hitch. That rarely happens!
Thanks!

@jaspermdegroot
jQuery Foundation member

Link to the PR for this feature: #3520
This PR was closed, not merged, because there was too much jumpiness.

@toddparker

Closing as a feature request, but we'll give this another look for a later release.

@toddparker toddparker closed this Sep 24, 2012
@jostster

@toddparker http://m.box.com does this very smoothly. Can you work with them to see how they achieved this?

@dan-mckay

Thanks for the code, great job.

@jaspermdegroot
jQuery Foundation member

I removed the feature request label and milestone 1.4 from this ticket. We will use #5394 as ticket for this feature now we are looking into the solution offered there.

@mtigue

Wow, worked like a charm. Thanks so much.

@frankygalore

That's f*ckin' amazing! Thank you so much! You guys made my day!

@mzestars

I'm still new with jquery. How do i add this to my page?

@mzestars

thanks 👍

@reyandersen

Thanks a bunch.
For my own use I changed it slightly, so that it only scrolls if the top of the expanding collapsible is not visible

if (expandableTop < $window.scrollTop())

@bpnyc

Hi,
Thank you very much for the code. It was working great but I upgraded to jquery.mobile-1.3.2 and the .live function is no longer supported, so I've updated it to use .on

$(document).on("expand", 'div.ui-collapsible-set', function(e) {
var top = $(e.target).offset().top;
if ($(window).scrollTop() > top)
$(window).scrollTop(top);
});

@fjbotto

Hi, all, i had made my function to get this done, because none of those functions worked for me.
So my code, if it helps to anyone here it is:

var that = "";
function binEventHandlers(){
$( "a.ui-collapsible-heading-toggle" ).on("click", fncClick);
}
function fncClick(){
that = $(this);
var timeoutId = setTimeout(function(){fncAnimate()},100);
}
function fncAnimate(){
$('html, body').animate({scrollTop: that.offset().top});
}
$(document).bind("pageinit", function(event, ui) {
binEventHandlers();

});

@shvoldum

Hi,

has anyone successfully updated the code below (posted by ricksuggs) to Jquey Mobile 1.45? This is exactly what I need, but I'm having a hard time implementing it..

var lastExpanded;
$('div.ui-collapsible-contain').live('expand', function() {
var $expandable = $(this);
// wait until the lastExpanded is collapsed
var intervalId = setInterval(function() {
if (lastExpanded && lastExpanded.has( ".ui-collapsible-heading-collapsed" )) {
var expandableTop = $expandable.offset().top,
$window = $(window),
targetPos = expandableTop - $window.scrollTop() + $expandable.height();
if (targetPos > $window.height() || expandableTop < $window.scrollTop()) {
$.mobile.silentScroll(expandableTop);
}
clearInterval(intervalId);
lastExpanded = $expandable;
} else {
lastExpanded = $expandable;
}
}, 200);
});

Any input is appreciated!

Thanks!

@johnbender johnbender was unassigned by shvoldum Feb 17, 2016
@anthonyac

@shvoldum,

you might want to have a look at this #5394, working well in 1.4.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment