Search code examples
javascriptjquerybackbone.jsmarionette

Capture scroll event in Backbone


I have a Backbone.Marionette item view. It renders a list of items. I want to listen for the scoll event everytime somebody scrolls the list. I assumed this would work:

events: {
    'scroll ul': 'filterInteraction'
},

filterInteraction: function(){
    console.log('in filterInteraction ');
}

But it does not capture the scroll event. However, when I do:

onRender: function() {
     this.$el.find('ul').on( 'scroll', function(){
         console.log('scroll event captured'):  
     });
}

This will capture the scroll event. What is the difference? Both seem to be doing the same thing...


Solution

  • We have 4 event handler :

    • scroll
      • for root div : el
      • for ul
    • click
      • for root div : el
      • for ul

    the 'click' event bubble so in event delagation the div #root receive it and can handle it, but the scroll event don't bubble so we can't handle it from #root div

    In the next example we have the same code for each event.

    If we click on 'ul' we have a log click for ul and a log click for #root because click event 'bubble' / climb up the DOM tree until #root.
    If we scroll on #root we have a log scroll for root because we capture the event directly from it.
    But we can't use event delegation to handle scroll from ul because scroll event don't 'bubble' / climb up the DOM tree.

    scroll on w3 site

    var dbg = $('#dbg')
    var log = function(val){
      dbg.append('<div>' + val + '</div>')
      .scrollTop(99999);
    };
    $('button').click(function(){dbg.empty() });
    
    
    
    var i=0;
    var MyView = Backbone.View.extend({
      
      events : {
        
        'click' : 'elClick' ,
        'scroll' :'elScroll' ,
        
        'click ul' : 'ulClick' ,
        'scroll ul' :'ulScroll' ,
    
      } ,
      elScroll : function(){ log('scroll for #root : '  + (i++)); } ,
      ulScroll : function(){ log('scroll for ul : '     + (i++)); } ,
      elClick  : function(){ log('clicked on #root :  ' + (i++)); } ,
      ulClick  : function(){ log('clicked on ul  : '    + (i++)); } ,
    }); 
    
    myView = new MyView({el : $('#root') });
    #dbg{
      position: aboslute;
      border : solid 1px #EEE;
      top : 0;
      left : 0;
      right :0;
      height : 150px;
      min-height : 150px;
      overflow : auto;
      bottom : auto;
    }
    #dbg:hover{
        bottom : 0;
        height : auto;
    }
    
    #root{
        position: aboslute;
      border : solid 1px #EEE;
      top : 30px;
      left : 0;
      right :0;
      height : 150px;
      overflow : auto
      }
    ul,li {
      border:solid 1px #CCC;
      list-style : none;
      padding : 0px;
      margin : 1px;
      cursor : pointer;
      }
    ul{
      height : 200px;
      overflow : auto; 
      }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="http://underscorejs.org/underscore-min.js"></script>
    <script src="http://backbonejs.org/backbone-min.js"></script>
    
    <div id='dbg'>debug : </div>
    <div id='root'>
      <ul>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        <li>A</li>
        
      </ul>
      
    </div><button>clear debug</button>