1

I'm tearing my hair off on this one. I'm new to jQuery Mobile and I have a function that loads new content whenever the browser has scrolled to the bottom of the page.

I also have a <select> where you can chose category. It works fine on the start page (i.e. when no category has been chosen). But as soon as I select a category, and then scroll to the bottom, the function bindScroll() triggers twice.

I've been working with this for almost two days trying to find some solution, but nothing. I havn't really figured out the different jQuery Mobile events yet, so there might be some problem there.

Please look at my code and help if you can. The site is built in .NET MVC, but the problem lies with the jQuery.

@using Namespace.Helpers
@{
    ViewBag.Title = "Home Page";
}
<!-- Get a drop down of the different categories -->
@Html.Raw(Html.GetCategories(true, "CategoryId", 0, true))

<!-- list view to append the fetched ads to -->
<ul data-role="listview" data-inset="true" id="ad-list">

</ul>

<script>
    // keeps track of how many rows to skip in the db. this is passed along to the server side
    var currentPos = 0;

    // save the categoryId
    var categoryId = $('#CategoryId').val();

    $('#page-start').live('pagecreate', function () {

        // load the ads for the first call
        loadAds();


        //handle the category drop down
        $('#CategoryId').change(function () {
            // clear the list of ads
            $('#ad-list').empty();

            // reset so we start fetching from the first row in the db, used on server side
            currentPos = 0;

            // update the category value to pass along to the server
            categoryId = $('#CategoryId').val();

            // just to know that it has a value
            console.log(categoryId);

            // re-load the new ads
            loadAds();

        });


    });

    // method that loads ads via AJAX
    function loadAds() {
        console.log('loadAds()');
        $.ajax({
            // method on the server that returns a partial view
            url: '/Home/LoadMoreAds',
            type: 'GET',
            data: {
                // pass along some data
                currentPosition: currentPos,
                categoryId: categoryId
            },
            success: function (result) {
                // add the result to the ad-list
                $('#ad-list').append(result);
                $('#ad-list').listview('refresh');

                // once again, bind the scroll event
                $(window).scroll(bindScroll);

            },
            error: function (data, textStatus, jqXHR) {
                alert(textStatus);
            }

        });

    }

    // method that checks if the scroll is near the bottom of the page
    function bindScroll() {
        if($(document).height() > $(window).height())
        {
            if ($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
                $(window).unbind('scroll');

                // just to know that the method has run
                console.log('bindScroll()');

                // update counter to skip the already loaded rows
                currentPos++;

                // load new ads
                loadAds();

            }
        }
    }

</script>

Edited answer: -----------------------------------------------

I went with suggestions from Mike C to not bind and re-bind the scroll event. Just one bind when page init. And then I used this code:

// method that checks if the scroll is near the bottom of the page
    var scrollHappening = false;
    function bindScroll() {
        if (scrollHappening) {
            return false;
        } else {
            if ($(document).height() > $(window).height()) {
                if ($(window).scrollTop() + $(window).height() > $(document).height() - 100) {

                    // just to know that the method has run
                    console.log('bindScroll()');

                    // update counter to skip the already loaded rows
                    currentPos++;

                    // load new ads
                    loadAds();

                    scrollHappening = true;

                }
            }
        }
    }

And set the scrollHappening = false in the success: of the ajax call. Seems to work pretty good!

Mikael Edebro
  • 241
  • 2
  • 13

1 Answers1

0

You rebind the bindScroll at this location after selecting a category, hence it gets called twice!? I.e. when you select a category, you make a call to LoadAds() which has this:

success: function (result) {
                    // add the result to the ad-list
                    $('#ad-list').append(result);
                    $('#ad-list').listview('refresh');

                    // once again, bind the scroll event
                    $(window).scroll(bindScroll);

                },

Every time you call LoadAdds(), this function adds an extra event for calling bindscroll.

  1. LoadAdds() You now have 1 event bound on scroll so scroll --> bindscroll == 1 event bound
  2. LoadAdds() You now have 2 events bound so scroll --> bindscroll == 2 events bound

When you actually scroll, if you have 2 events bound to bindscroll, it'll call both events before the unbind happens is my guess.

I think your real solution here, is to not bind and unbind all the time. Bind a single time and do not play this game with bind/unbind. Alter your code to work with a single bind. At the bottom, have a variable to mark if you are already at the bottom and just exit the function if you are. Or something similar. You're creating a headache for yourself with this bind/unbind business.

Mike C.
  • 3,024
  • 2
  • 21
  • 18
  • Thanks for the effort, but this doesn't help unfortunately. The odd thing is that the scroll event shouldn't be re-binded until the ajax sucess method, but somehow it gets triggered. Also strange that it only appears when I have chosen a category, otherwise it runs smoothly. – Mikael Edebro Feb 28 '13 at 14:10
  • Ahh why didn't you say so! Now it seems more obvious. I've edited my answer. – Mike C. Feb 28 '13 at 14:15
  • I don't understand. That is exactly the same as the original code. When the bindScroll() runs, I un-bind the scroll and load the ads, and after the ads have been loaded into the list, I re-bind the scroll. Or at least that's my intention. What drives me mad is that it works fine when i show "all categories". – Mikael Edebro Feb 28 '13 at 15:24
  • That seems resonable. But shouldn't this event be un-bound and removed? Is there any way of removing it completely? – Mikael Edebro Feb 28 '13 at 15:52