bodacious
bodacious

Reputation: 6705

How can I scroll to a page element in jQuery Mobile?

I have a long jQuery mobile page and would like to scroll to an element halfway down this page after the page loads.

So far I've tried a few things, the most successful being:

jQuery(document).bind("mobileinit", function() {
  var target;
  // if there's an element with id 'current_user'
  if ($("#current_user").length > 0) {
    // find this element's offset position
    target = $("#current_user").get(0).offsetTop;
    // scroll the page to that position
    return $.mobile.silentScroll(target);
  }
});

This works but then the page position is reset when the DOM is fully loaded. Can anyone suggest a better approach?

Thanks

Upvotes: 4

Views: 8451

Answers (3)

fbonnet
fbonnet

Reputation: 2299

A bit late, but I think I have a reliable solution with no need for setTimeout(). After a quick look into the code, it seems that JQM 1.2.0 issues a silentScroll(0) on window.load for chromeless viewport on iOS. See jquery.mobile-1.2.0.js, line 9145:

    // window load event
    // hide iOS browser chrome on load
    $window.load( $.mobile.silentScroll );

What happens is that this conflicts with applicative calls to silentScroll(). Called too early, the framework scrolls back to top. Called too late, the UI flashes.

The solution is to bind a one-shot handler to the 'silentscroll' event that calls window.scrollTo() directly (silentScroll() is little more than an asynchronous window.scrollTo() anyway). That way, we capture the first JQM-issued silentScroll(0) and scroll to our position immediately.

For example, here is the code I use for deep linking to named elements (be sure to disable ajax load on inbound links with data-ajax="false"). Known anchor names are #unread and #p<ID>. The header is fixed and uses the #header ID.

$(document).bind('pageshow',function(e) {
    var $anchor;
    console.log("location.hash="+location.hash);
    if (location.hash == "#unread" || location.hash.substr(0,2) == "#p") {
        // Use anchor name as ID for the element to scroll to.
        $anchor = $(location.hash);
    }
    if ($anchor) {
        // Get y pos of anchor element.
        var pos = $anchor.offset().top;

        // Our header is fixed so offset pos by height.
        pos -= $('#header').outerHeight();

        // Don't use silentScroll() as it interferes with the automatic 
        // silentScroll(0) call done by JQM on page load. Instead, register
        // a one-shot 'silentscroll' handler that performs a plain
        // window.scrollTo() afterward.
        $(document).bind('silentscroll',function(e,data) {
            $(this).unbind(e);
            window.scrollTo(0, pos);
        });
    }
});

No more UI flashes, and it seems to work reliably.

Upvotes: 10

thefly73
thefly73

Reputation: 21

I was digging a lot this issue, also at jQuery mobile official forum.

Currently it seems that there is no solution (at least for me).

I tried different events (mobileinit, pageshow) and different functions (silentscroll, scrolltop) as suggested above, but, as a result, I always have page scrolled until all images and html is finished loading, when page is scrolled to top again!

Partial and not really efficient solution is using a timer as suggested in comment to sgliser's answer; unfortunately with a timeout is difficult to know when page will be fully loaded and if scroll happened before that, it will scroll back to top at the end of load, while if it happens too long after page has fully loaded, the user is already scrolling page manually, and further automated scroll will create confusion.

Additionally, would be useful to have silentscroll or other function to address a specific id or class and not plain pixels, because with different browsers, resolutions and devices it may give different and not correct positioning of the scroll.

Hope someone will find a smarter and more efficient solution than this.

Upvotes: 0

sgliser
sgliser

Reputation: 2071

The event you're looking for is "pageshow".

Upvotes: 3

Related Questions