Why I stopped using ng-grid and rolled my own with ReactJS

In a previous post, I talked about ng-grid and ng-table as possible components to use for a very cool project I was building at my company.

This project required the use of grids or tables to display tabular data so I figured that using one of the two options above was a no brainer for an AngularJS application.

I made the decision to go with ng-grid. It has all of the features I need to support right out of the box and it seems to work (of course) very well with Angular.

I went ahead implemented ng-grid into the project and eventually finished the whole thing and delivered it.

The project was a great success and improved UX has been welcomed by the users with open arms.

There was however one big elephant in the room, and that was the grid. It rendered somewhat fast (~1500ms - with 25 rows and about 10 columns).

Now, as soon as you would change the page size to 100 records and added columns to the grid, it would still render somewhat okay (~1700ms) but scrolling performance was horrendus.

I get that ng-grid is based off SlickGrid and uses virtualization to not render the full data set, but I am not sure this works well with Angular and the performance issues you run into when you have 2000+ bindings on the page.

I knew I could not be happy with this project until I fixed this problem. I tried a lot things with ng-grid, using bindonce, and other suggestions but the performance gain would usually create a bug in one of the grids where I was expecting the bindings to work as usual.

At the time, I thought to myself that I should switch to ng-table. But I had written so much code already that the ng-table seemed too expensive.

That's when I decided to create a proof of concept with one of the bigger grids and render it with ReactJS.

I created an AngularJS directive called reactGrid, and tried to support ng-grid's api as much as possible (with some minor changes).

My directive looked something like this:

link: function(scope, element, attrs) {

    var gridDefault = {
            columnDefs: [],
            data: [],
            maxHeight: 800
    };

    var grid = _.extend(gridDefault, scope.grid);

    var render = function(grid) {
        React.renderComponent(Grid( {grid: grid} ), element[0]);
    };

    scope.$watch("grid.data", function(newValue, oldValue) {
        _.extend(grid, {data: newValue});
        render(grid);
    });

    ReactGridService.updateColumns = function(columns) {
        _.extend(grid, {columnDefs: columns});
        render(grid);
    };

    render(grid);

}

Essentially, AngularJS acts as the Dispatcher and Store in the Flux architecture explained at f8: http://facebook.github.io/react/blog/2014/05/06/flux.html

From there, I wrote my Grid component in ReactJS (in about 440 lines non-minified) which supports all of the ng-grid features I needed.

This completely fixed my performance woes, the grid now renders 100 rows with 10 columns in about ~400ms, and the scrolling performance is blazing fast.

The end users certainly noticed a difference and were very happy with the performance. I am also really pleased with the results and I am glad to have ReactJS in my tool belt along with AngularJS.

I am still a big supporter of Angular and will keep using it to develop web applications but I will start to ship off the rendering job off to ReactJS whenever I run into scenarios where I have to render a lot of data.

All in all, really impressed with ReactJS, jsx is nice once you get used to it and I love React's methodology of writing components to look the way they should at any point in time (with different states and data).

I leave you guys with a tease of the react component:

return React.createClass({  
        render: function() {
            return (
                <div>
                    <div className="ngReactGridHeader">
                        <GridHeader columns={this.props.grid.columnDefs} grid={this.props.grid} />
                    </div>
                    <div className="ngReactGridBody">
                        <GridBody columns={this.props.grid.columnDefs} data={this.props.grid.data} grid={this.props.grid} />
                    </div>
                </div>
            )
        }
    });

Maybe in the future I will decouple this code into an open source component that I can fully share with you guys.

Update: Here is the github link for this code: https://github.com/josebalius/ngReactGrid