Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Ember Virtual List Component</title>
  <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.1/normalize.css">
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
  <script src="http://builds.emberjs.com/tags/v1.13.5/ember-template-compiler.js"></script>
  <script src="http://builds.emberjs.com/tags/v1.13.5/ember.debug.js"></script>
</head>
<body>
  <script type="text/x-handlebars">
    <h1>Scroll Scroll</h1>
    {{outlet}}
  </script>
    <script type="text/x-handlebars" id="components/x-virtual-list">
    <div id="container">
      <div id="scroller" style={{scrollerStyle}}>
        {{#each visibleItems as |item|}}
          <div class="item" style={{item.style}}>{{item.name}}</div>
        {{/each}}
      </div>
    </div>
    <div>
      <p>scroll offset: {{scrollOffset}}</p>
      <p>visible elements: {{visibleItems.length}}</p>      
      <p>start offset: {{startOffset}}</p>      
      <p>end offset: {{endOffset}}</p>      
      <p>start index: {{startIndex}}</p>      
      <p>end index: {{endIndex}}</p>      
    </div>  
  </script>
  
  <script type="text/x-handlebars" data-template-name="index">
    {{x-virtual-list items=model}}
  </script>
</body>
</html>
 
/* Put your CSS here */
html, body {
  margin: 20px;
  box-sizing: border-box;
}
h1, h2 {
  font-weight: normal;
}
#container {
  width: 300px;
  height: 200px;
  outline: 1px solid black;
  overflow: scroll;
  position: relative;
}
#scroller {
  position: absolute;
  background-color: blue;
  width: 100%;
}
.item {
  position: absolute;
  outline: 1px solid white;
  height: 40px;
  width: calc(100% - 10px);
  line-height: 40px;
  padding-left: 10px;
  color: white;
  background-color: green;
}
 
App = Ember.Application.create();
App.Router.map(function() {
  // put your routes here
});
App.IndexRoute = Ember.Route.extend({
  model: function() {
    var people = [
      'Bill', 
      'Zach', 
      'Seung',
      'Kapil', 
      'Tom', 
      'Ren',
      'George', 
      'Ed', 
      'Ben',
      'Curtis', 
      'Allie', 
      'Tao',
      'David', 
      'Gian', 
      'Clifton',
      'Richard', 
      'Max', 
      'Tony',
      'Kiran', 
      'Mike', 
      'Brian',
      'Joe',
      'Matt',
      'Alex',
      'Jeremy',
      'Travis'
    ];
    var items = [];
    for (var i = 0; i < 1000; i++) {
      var person = people[Math.floor(Math.random() * people.length)];
      items.push((i+1) + ". " + person);
    }
    return items;
  }
});
App.XVirtualListComponent = Ember.Component.extend({
  rowHeight: 40,
  scrollOffset: 0,
  containerHeight: 0,
  
  visibleItems: function() {
    var rowHeight = this.get('rowHeight');
    var startIndex = this.get('startIndex');
    var endIndex = this.get('endIndex');
    return this.get('items').slice(startIndex, endIndex).map(function(name, i) { 
      var index = i + startIndex;
      var top = (rowHeight * index);
      return {
        name: name,
        style: new Ember.Handlebars.SafeString("top: " + top + "px;")
      };
    });
  }.property('items', 'rowHeight', 'startIndex', 'endIndex'),
  
  startOffset: function() {
    return Math.abs(this.get('scrollOffset')) / this.get('rowHeight');
  }.property('scrollOffset', 'containerHeight', 'rowHeight'),
  endOffset: function() {
    return (Math.abs(this.get('scrollOffset')) + this.getWithDefault('containerHeight', 0)) / this.get('rowHeight');
  }.property('scrollOffset', 'containerHeight', 'rowHeight'),
  startIndex: function() {
    return Math.floor(this.get('startOffset'));
  }.property('startOffset'),
  endIndex: function() {
    return Math.ceil(this.get('endOffset'));
  }.property('endOffset'),
  scrollerStyle: function() {
    var height = this.get('items.length') * this.get('rowHeight');
    var style = "height: " + height + "px";
    return new Ember.Handlebars.SafeString(style);
  }.property('items.length', 'rowHeight'),
  
  hookupScroll: function() {
     var view = this;
     $('#container').bind('scroll', function() {
       Ember.run.once(view, function() {
         var containerOffset = $('#container').offset().top;
         var scrollerOffset = $('#scroller').offset().top;
         var scrollOffset = scrollerOffset - containerOffset;
         view.set('scrollOffset', scrollOffset);
       });
     });
  }.on('didInsertElement'),
  
  readySetGo: function() {
    Ember.run.later(this, function() {
      this.set('containerHeight', Ember.$('#container').height());      
    });
  }.on('didInsertElement'),
  
});
Output

This bin was created anonymously and its free preview time has expired (learn why). — Get a free unrestricted account

Dismiss x
public
Bin info
anonymouspro
0viewers