11

When I started working on my current project I was given quite an arduous task - to build something that in essence suppose to replace big spreadsheet people use internally in my company.

That's why we I thought a paginated table would never work, and quite honestly I think pagination is stupid. Displaying dynamically changing data on a paginated table is lame. Say an item on page #2 with next data update can land on page whatever.

So we needed to build a grid with nice infinite scroll. Don't get me wrong, I've tried many different solutions. First, I built vanilla ng-repeat thing and tried using ng-infinite-scroll, and then ng-scroll from UI.Utils. That quickly get me to the point where scrolling became painfully slow, and I haven't even had used any crazy stuff like complicated cell templates, ng-ifs or filters. Very soon performance became my biggest pain. When I started adding stuff like resizable columns and custom cell templates, no browser could handle all those bindings anymore.

Then I tried ng-grid, and at first I kinda liked it - easy to use, it has a few nice features I needed, but soon I realized - ng-grid is awful. Current version stuffed with bugs, all contributors stopped fixing those and switched to work on a next version. And only God knows when that will be ready to use. ng-grid turned out to be pretty much worse than even vanilla ng-repeat.

I kept trying to find something better. trNgGrid looked good, but way too simplistic and doesn't offer features I was looking for out of the box.

ng-table didn't look much different from ng-grid, probably it would've caused me same performance issues.

And of course I needed to find a way to optimize bindings. Tried bind-once - wasn't satisfied, grid was still laggy. (upd: angular 1.3 offers {{::foo}} syntax for one-time binding)

Then I tried React. Initial experiment looked promising, but in order to build something more complicated I need to learn React specifics, besides that thing feels kinda non-anguleresque and who knows how to test directives built with angular+react. All my efforts to build nice automated testing failed - I couldn't find a way to make React and PhanthomJS to like each other (which is probably more Phantom's problem. is there better headless browser) Also React doesn't solve "appending to DOM" problem - when you push new elements into the data array, for a few milliseconds browser blocks the UI thread. That of course is completely different type of problem.

My colleague (who's working on server-side of things) after seeing my struggles, grumbled to me that I already spent too much, trying to solve performance problems. He made me to try SlickGrid, telling me stories how this is freakin zee best grid widget. I honestly tried it, and quickly wanted to burn my computer. That thing completely depends on jQuery and bunch of jQueryUI plugins and I refuse to suddenly drop to medieval times of web-development and lose all angular goodness. No, thank you.

Then I came by ux-angularjs-datagrid, and I really, really, really liked it. It uses some smart bad-ass algorithm to keep things very responsive. Project is young, yet looks very promising. I was able to build some basic grid with lots of rows (I mean huge number of rows) without straying too much from the way of angular zen and scrolling still smooth. Unfortunately it's not a complete grid widget solution - you won't have resizable columns and other things out of the box, documentation is somewhat lacking, etc.

Also I found this article, and had mixed feelings about it, these guys applied a few non-documented hacks to angular and most probably those would breaks with feature versions of angular.

Of course there are at least couple of paid options like Wijmo and Kendo UI. Those are compatible with angular, however examples shown are quite simple paginated tables and I'm not sure if it is worth even trying them. I might end-up having same performance issues. Also you can't selectively pay just for the grid widget, you have to buy entire suite - full of shit I probably never use.

So, finally to my question - is there good, guaranteed, less painful way to have nice grid with infinite scrolling? Can someone point to good examples, projects or web-pages? Is it safe to use ux-angularjs-datagrid or better to build my own thing using angular and react? Anybody ever tried Kendo or Wijmo grids?

Please! Don't vote for closing this question, I know there are a lot of similar questions on stackoverflow, and I read through almost every single one of them, yet the question remains open.

iLemming
  • 30,282
  • 53
  • 181
  • 302
  • this will be a very opinionated exchange, not to mention the incredible amount of text and references, so I think it will be closed – Devin Sep 04 '14 at 23:40
  • I just can't believe every single grid widget out there, compatible with angular suffers from poor performance problems. – iLemming Sep 04 '14 at 23:49
  • How many rows are we talking about here? – link64 Sep 05 '14 at 00:32
  • well, my ng-grid would start slowing down with less than 500 rows in it – iLemming Sep 05 '14 at 05:22
  • The grids/you are trying to force a limited programming language to do a big task the wrong way. Since the beginning of time the way to solve scrolling/large content areas is by illusion. Show what is needed on the screen and remove the rest. Regardless if its a listbox in Windows, Angular/HTML or a computer game. I.e. keep the same UI-components and binding, but use an offset (bound to scrollbar position) to determine content. Most/all grids do it the "easy" way, just paint it all out. So for large grids pagination is the simple solution. – Tedd Hansen Oct 08 '14 at 07:06
  • And; Only because AngularJS is new doesn't mean jQuery is from "medieval times of web-development". You use the right tool for the job and AngularJS is not the messiahs - that I think is only a common belief among newcomers to our great profession. If it solves the problem then you use jQuery.1. A developer must write code that creates value. 2. A developer must make their code easy to maintain, except where such expenditure will conflict with the first law. 3. A developer must reduce their code to the smallest size possible, as long as such reduction does not conflict with the first two laws. – Tedd Hansen Oct 08 '14 at 07:12

2 Answers2

5

Maybe the problem is not with the existing widgets but more with the way you use it. You have to understand that over 2000 bindings angular digest cycles can take too long for the UI to render smoothly. In the same idea the more html nodes you have on your page, the more memory you will use and you might reach the browser capacity to render so many nodes in a smooth way. This is one of the reason why people use this "lame" pagination.

At the end what you need to achieve to get something "smooth" is to limit the amount of displayed data on the page. To make it transparent you can do pagination on scroll.

This plunker shows you the idea, with smart-table. When scrolling down, the next page is loaded (you will have to implement the previous page when scrolling up). And at any time the maximum amount of rows is 40.

function getData(tableState) {

            //here you could create a query string from tableState
            //fake ajax call
            $scope.isLoading = true;

            $timeout(function () {

                //if we reset (like after a search or an order)
                if (tableState.pagination.start === 0) {
                    $scope.rowCollection = getAPage();
                } else {
                    //we load more
                    $scope.rowCollection = $scope.rowCollection.concat(getAPage());

                    //remove first nodes if needed
                    if (lastStart < tableState.pagination.start && $scope.rowCollection.length > maxNodes) {
                        //remove the first nodes
                        $scope.rowCollection.splice(0, 20);
                    }
                }

                lastStart = tableState.pagination.start;

                $scope.isLoading = false;
            }, 1000);

        }

This function is called whenever the user scroll down and reach a threshold (with throttle of course for performance reason)

but the important part is where you remove the first entries in the model if you have loaded more than a given amount of data.

laurent
  • 2,500
  • 16
  • 25
  • And of course you realize that your pkunker is actually good demonstration of the problems I'm talking about. UI gets blocked while rowCollection gets updated. Yes, it just a few milliseconds, yet it's noticeable and annoying – iLemming Oct 08 '14 at 19:23
  • The UI is actually blocked 1000 ms in the timeout which is supposed to mimic server call, but then you can be smarter an load one or two pages in advance, so the loading time become transparent – laurent Oct 09 '14 at 12:41
2

I'd like to bring your attention towards Angular Grid. I had the exactly same problems as you said, so ended up writing (and sharing) my own grid widget. It can handle very large datasets and it has excellent scrolling.

Ceolter
  • 91
  • 3