AngularJS UI Table View

AngularJS virtual scroller designed for mobile first.

Jamie Sutherland
AngularJS Articles

--

Yea yea, blah blah blah, I just want the scroller!

For those that just want to get stuck in. Proceed forthwith.

http://angular-ui-table-view.mallzee.com

Check it out, fork it, fix it, or chat to me about it on twitter. @wedgybo.

Why are we talking about another scroller?

There are plenty of virtual scrollers out there these days. So why have I gone to the bother of writing up about another one? Well. Most of the ones out there are designed for the desktop. The ones that I tried, and believe me. I tried many, just weren’t quite right on a mobile device. Plus I wanted to build something for AngularJS that didn’t rely on any external libraries, in the hope that we could make scrolling in our mobile apps glide with grace.

Silky smooth

There are two major hurdles to get over with mobile.

  1. Large amounts of DOM in your application kills performance.
  2. Scrolling events and calculation are hard on mobile

First you have the same problem that exists on desktop. The reason these virtual scrollers exist in the first place is because loading tens of thousands of DOM elements into your pages kills performance. While displaying a list of ten thousand items on your desktop app might make the browser a little janky when scrolling. It will 100% kill a mobile application.

Some great people started coming up with solutions by faking the size of the scrolling element to make it appear like the content is huge, but only display enough DOM elements to show on the screen, plus a buffer either side. Then they create and delete elements as you scroll so they appear like it’s one continuous list. Happy days. This solution is great on the desktop and has been for a while now. It’s what we’ve mirrored in this solution.

Second is mobiles dirty little secret. It doesn’t like you scrolling.

HTML5 on mobile devices + scrolling big lists = Massive headache.

There is no continuous scroll event when you flick your view up and down. You get sporadic events, only when your finger is touching the screen. This makes life a hard when you want to create that smooth native feel. So here’s our solution which is trying to get that native feel for HTML5

https://github.com/mallzee/angular-ui-table-view

Technical shenanigans

The concept is based around ng-repeat track by feature to stop DOM creation and deletion, which is slow on mobile devices. Too slow when scrolling.

The directive is called mlz-ui-table-view. It holds all the information about the view, buffer, scroll position, items list, subset of items, etc. This is the only directive required to control your child ng-repeat.

Markup to create the virtual list.
Overview of the scrollers key parts and how it works

Scrolling

When a scroll event is detected. Models which map the buffer position, view position and scroll position are all updated based on the scrollPos of the container and the specified row height of the items. The key elements here are the position, the scroll directions, and if the direction has changed

View

The view tracks the position of what the user is actually seeing. This is so we can calculate where the buffered elements should be moved to based on the view’s position and scroll direction.

Buffer

This is the list of DOM elements that are moved around the scroll wrapper to give the appearance of a full list.

Dead Zones

These are area’s on the scroller that have no effect on the buffer. If the view’s edges stay in these dead zones, the render process can be skipped.

Trigger Zones

These are area’s that can trigger events, most commonly used to load more data into the main items array. It can be useful for virtual pagination by triggering a function on your scope when either end is reached.

How does it work?

The UITableView works by trying to keep the buffer as long as possible in the direction of travel. So if you are scrolling down the list. There is no point in showing anything directly above the view. As soon as there is an index change detected on the top edge, a calculation is made to workout how many indexes we have passed since the last event. Then all those elements are moved to the other end of the list in the correct order and updated with the relative items data to create the illusion of a never ending list.

When the direction of travel is changed. The buffer automatically jumps as far as possible in the direction of travel. This is to avoid whitespace when the scroll speed gets too high.

Performance

I’ve got the following FPS graphs from my Chrome Inspector and Instruments. You can see on the mobile device, it’s sitting at an average of 50fps. This was with heavy and varied scrolling. On the desktop it gives it no problems what so ever. I believe the performance can be improved further with a greater understanding and simplifying of ng-repeat specifically for this directive and further improvements to the current code.

Running on an iPhone 4s with a list of appox 200 items. Buffer size = 10 elements each with a height of 150px
Chrome 32 on a 2011 Macbook Pro running Lion

--

--

Jamie Sutherland
AngularJS Articles

CTO @ Mallzee / Co-Founder @ Newbridge Green. Developer, Snowboarder, Runner, & Footballer.