Endless/infinite scroll type solution with backbone.js
Asked Answered
E

6

14

I'm toying around with backbone.js and I'm wondering if there is more concise solution for creating an 'endless-scroll' situation for models/collection than the modules I've been looking at (there are several for jquery, probably more for other libraries).

Some searching turned up next to nothing, so I thought I'd ask before getting into trying to build my own solution with backbone, if it something I should build outside a backbone collection, or if someone has attempted something similar.

Exceptional answered 23/5, 2011 at 19:51 Comment(0)
Q
10

This blog post landed on my twitter stream recently. Looks like a very nice solution and works well on the main page. From the blog the benefits of this solution are:

  1. Preserves the back button.
  2. Does NOT use the hashbang, no matter how happy twitter engineers are with it.
  3. Gives up on infinitely scrolling if (1) is impossible.
  4. Progressively enhances: when (3) occurs, the user follows a good ol' hyperlink for more content.
Quatrefoil answered 23/5, 2011 at 20:17 Comment(4)
That is interesting, I'll look into it.Exceptional
I just wrote an infinite scroll tutorial also backbonetutorials.com/infinite-scrollingGotland
The article gives very good points. However, personally I'd say don't freak out about non-js fallbacks developer.yahoo.com/blogs/ydn/…Superincumbent
@Superincumbent Agreed, although historically for the sites I have worked on it was a requirement to support non-js for accessibility reasons and support for screen readers. I believe screen readers are much better at interpreting JavaScript and dynamic pages now.Quatrefoil
A
4

I found two other resources while researching this myself:

  1. https://github.com/joneath/infiniScroll.js
  2. http://addyosmani.com/blog/backbone-paginator-new-pagination-components-for-backbone-js/
Anne answered 10/4, 2012 at 1:42 Comment(0)
J
1

SlickGrid could be an option if you haven't tried it: https://github.com/mleibman/SlickGrid/wiki/Examples

Jamison answered 23/5, 2011 at 21:50 Comment(1)
Seems interesting and I've seen it before but seems too heavy for some light uses I want right now.Exceptional
S
0

Another solution with Backbone and jQuery waypoints: https://gist.github.com/davidmontoyago/6336612

Selig answered 30/8, 2013 at 14:37 Comment(0)
C
0

Following extension should work: https://github.com/joneath/infiniScroll.js

These may also be useful to load data partially: http://backplug.io/plugin/Backbone.actAs.Paginatable, https://github.com/wyuenho/backbone-pageable, https://github.com/backbone-paginator/backbone.paginator.

I prefer searching Backbone extensions here: http://backplug.io.

Conformance answered 30/8, 2013 at 16:44 Comment(0)
E
-1

Another repeated answer: Here is my extension of Backbone.Collection:

_.extend Backbone.Collection.prototype,
  options:
    infinitescroll:
      success: $.noop
      error: $.noop
      bufferPx: 40
      scrollPx: 150
      page:
        current: 0
        per: null
      state:
          isDuringAjax: false
          isDone: false
          isInvalid: false
      loading:
        wrapper: 'backbone-infinitescroll-wrapper'
        loadingId: 'backbone-infinitescroll-loading'
        loadingImg: 'loading.gif'
        loadingMsg: '<em>Loading ...</em>'
        finishedMsg: '<em>No more</em>'
        msg: null
        speed: 'fast'

  infinitescroll: (options={})->
    # NOTE: coffeescript cannot deal with nested scope!
    that = @

    _.extend(@options.infinitescroll, options.infinitescroll) if options.infinitescroll

    infinitescroll_options = @options.infinitescroll

    # where we want to place the load message in?
    infinitescroll_options.loading.wrapper = $(infinitescroll_options.loading.wrapper)
    if !infinitescroll_options.loading.msg and infinitescroll_options.loading.wrapper.size() > 0
      infinitescroll_options.loading.msg = $('<div/>', {
        id: infinitescroll_options.loading.loadingId
      }).html('<img alt="'+$(infinitescroll_options.loading.loadingMsg).text()+'" src="' + infinitescroll_options.loading.loadingImg + '" /><div>' + infinitescroll_options.loading.loadingMsg + '</div>')
      infinitescroll_options.loading.msg.appendTo(infinitescroll_options.loading.wrapper).hide()
    else
      infinitescroll_options.loading.msg = null

    fetch_options = _.omit(options, 'infinitescroll')
    infinitescroll_fetch = ()=>
      # mark the XHR request
      infinitescroll_options.state.isDuringAjax = true

      # increase page count
      infinitescroll_options.page.current++

      payload = {
        page: infinitescroll_options.page.current
      }
      payload['limit'] = infinitescroll_options.page.per if infinitescroll_options.page.per isnt null

      _.extend(fetch_options, {
        remove: false
        data: payload
      })

      if infinitescroll_options.loading.msg
        # preload loading.loadingImg
        (new Image()).src = infinitescroll_options.loading.loadingImg if infinitescroll_options.loading.loadingImg

        infinitescroll_options.loading.msg.fadeIn infinitescroll_options.loading.speed, ()->
          that.fetch(fetch_options)
          .success (data, state, jqXHR)=>
            infinitescroll_options.state.isDuringAjax = false
            infinitescroll_options.state.isDone = true if _.size(data) is 0

            infinitescroll_options.loading.msg.fadeOut infinitescroll_options.loading.speed, ()->
              infinitescroll_options.success.call(data, state, jqXHR) if _.isFunction(infinitescroll_options.success)
              return
            return
          .error (data, state, jqXHR)=>
            infinitescroll_options.state.isDuringAjax = false
            infinitescroll_options.state.isInvalid = true

            infinitescroll_options.loading.msg.fadeOut infinitescroll_options.loading.speed, ()->
              infinitescroll_options.error.call(data, state, jqXHR) if _.isFunction(infinitescroll_options.error)
              return
            return
          return

      else
        that.fetch(fetch_options)
        .success (data, state, jqXHR)=>
          infinitescroll_options.state.isDuringAjax = false
          infinitescroll_options.state.isDone = true if _.size(data) is 0

          infinitescroll_options.success.call(data, state, jqXHR) if _.isFunction(infinitescroll_options.success)
          return

        .error (data, state, jqXHR)=>
          infinitescroll_options.state.isDuringAjax = false
          infinitescroll_options.state.isInvalid = true

          infinitescroll_options.error.call(data, state, jqXHR) if _.isFunction(infinitescroll_options.error)
          return
      return

    $(document).scroll ()->
      $doc = $(document)
      isNearBottom = ()->
        bottomPx = 0 + $doc.height() - $doc.scrollTop() - $(window).height()

        # if distance remaining in the scroll (including buffer) is less than expected?
        (bottomPx - infinitescroll_options.bufferPx) < infinitescroll_options.scrollPx

      return if infinitescroll_options.state.isDuringAjax || infinitescroll_options.state.isDone || infinitescroll_options.state.isInvalid || !isNearBottom()

      infinitescroll_fetch()
      return


    infinitescroll_fetch()
    return

https://gist.github.com/mcspring/7655861

Ellerd answered 26/11, 2013 at 10:8 Comment(1)
You can use the fat arrow => instead of the thin arrow and carry over the outer context to @ or _thisHydrograph

© 2022 - 2024 — McMap. All rights reserved.