AngularJs Virtual Repeater with a Grid
So I had a grid of images I displayed with an Angular ng-repeat, where the number of images was in the hundreds. This was just killing performance and overloading the DOM. I was getting super frustrated with the choppy scrolling and overall slow loading.
It occurred to me to use a virtual repeater, however, they either support vertical or horizontally stacked elements, not a grid. In order to get this to work, I need to structure my elements in a 2D array. That way I could still use the repeater on spitting out rows of image arrays and gain a performance boost through that.
2D Structure:
[
[img, img, img, img] ,
[img, img, img, img] ,
[img, img, img, img] ,
[img, img, img, img]
]
img = the image source url
The first thing I did, was make sure I knew the width of the total space for the grid and width of each element. I want to make sure I fill the space, so I did the math to know how many elements will fill the total space and that will be my column count. I recommend to setup some listeners on the grid width to catch changes from the user changing the window size, I won’t be showing that part in this example. The snippet below shows the creation of my 2D array that will be fed to the repeater.
//Passing in my array of images that I need to break down into a 2D array //Also, including the width of the entire grid space and each image's uniformed width function computeRows(imageArray, width, imageWidth) { var rows = []; if (imageArray) { const rowCount = width/ imageWidth; const copy = imageArray.slice(); //using a copy instead of affecting actual element while (copy.length) { //create the 2D array by looping through the imageArray and splicing it into chunks rows.push(copy.splice(0, rowCount)); } } return rows; } //Will need to bind computeRows() to the scope
Once I have my 2D array, I bound it to me scope and used it in my template. I chose to use vs-repeat because it was very quick and easy to implement.
<div vs-repeat vs-excess="10"> <div ng-repeat="row in rows"> <img ng-repeat="img in row" ng-src="{{img}}"/> </div> </div>
That was it, the end result was awesome, vs-repeat handled just showing what was necessary for the user experience and loading the remainder DOM elements as the user scrolled through the grid.