JSFiddle - React, Tailwind, and code Playground

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.js"></script>
<script src="https://raw.githubusercontent.com/angular-ui/ui-scroll/master/dist/ui-scroll.min.js"></script>
<div ng-app="scrollerTestApp" ng-controller="ScrollerController as c" ui-scroll-viewport class="scrollerViewport">
	<div ui-scroll="itemArray in imageDataSource" buffer-size="10" style="overflow:auto;">
        <div ng-repeat="item in itemArray" class="imageCell">
		    <img ng-src="{{item.imageURL}}" title="{{item.description}}"/>
        </div>
	</div>
</div>

CSS

body {
		font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande", "Lucida Sans", Arial, sans-serif;
	}

    .imageCell {
        float: left;
        height: 100px;
        width: 100px;
    }
	.scrollerViewport {
		position: fixed;
		top: 0;
		bottom:0;
        width: 500px;
	}

JavaScript

var appModule = angular.module('scrollerTestApp', ['ui.scroll'])
	.controller('ScrollerController', ['$scope', '$log', function($scope, $log) {
         
        var self = this;
		$scope.imageDataSourceAdapter = {};
         
		$scope.imageDataSource = {
            
			get : function (index, count, callback) {
                var itemsPerRow = 4
				var internalIndex = (index - 1) * itemsPerRow;
                var internalCount = (count + index - 1) * itemsPerRow;
                var i, items = [], tmpItems = [];
	
				$log.info ("data source get : index=" + index + ", count=" + count);

				// Catch cases where all requested items are below our lower limit
				if (index + count <= 1) {
					return callback ([]);
				}
	
				// Limit to items# >= 1
				/*if (index < 1)
					index = 1;*/
                
                var min = 0;
                var max = 1000;

				for (i=internalIndex; i< internalCount; i++) {
                    if(i < min || i > max) { 
                        continue;
                    }
                    
					var item = {
						description: "Item : " + (i + 1),
						imageURL: "http://placehold.it/96x96&text=" + (i + 1)
					};
                    
                    tmpItems.push(item);
                    if(i % itemsPerRow === 3) {
						items.push (tmpItems);
                        tmpItems = []
                    }
				}
				callback (items);
			}
		}
	}]);