; last updated - 8 minutes read
Fork me on GitHubThere are several data table widgets for Angular, but none of them matched our project's needs. I'm sure that's simply a matter of time. Angular2 is young, and the third-party libraries are even younger. They simply didn't have enough time to accumulate features and maturity. So why don't we use one of the seasoned JavaScript data tables?

(Update April 4, 2018: Keep in mind that the original version of this article has been written in Januar 2017).

As it turns out, Louis Lin had the same idea creating the Angular DataTables project. It looks promising, but at the time of writing, it was only 26 days old. So the feature list is pretty short. When you're reading this article, things have probably improved. However, today I don't want to tell you how to use a third-party data table. Instead, I'll tell you how to do it yourself. Before we start to wallow in the source code, let's start with what developers usually do: a short market survey. If you're in a hurry, skip that section or jump directly to the source code of the demo on GitHub.

Update April 4, 2018: By now, the datatable written by Louis has gained a lot of traction. It's definitely worth a look. Basically, it's a materialization of the ideas of this post: take the DataTables.net project, add a small Angular API and smooth the rough edges caused by integration what was never intended to be integrated.

Short Angular data table market survey (as of Jan 21, 2017 / updated Apr 4, 2018)

I've already mentioned Louis Lin's project. He does exactly what we're doing later in this article: integrating the table from DataTables.net. The demos look nice, and I guess you can pass almost every option of the JavaScript widget to the angular-datatables. If my guess is correct, compensates the lack of features the demos show.

"Lack of features" is not the word coming to mind looking at the demo of Swimlane's ngx-datatable. The only reason we didn't use it was because our project uses Bootstrap. ngx-datatable is based on Material Design, so this was a K.O. criterium in January 2017. In the meantime, they've added a Bootstrap theme, so currently I'm re-evaluating this component.

The ng2-table of valor-software is great because it's extremely simple. You provide a column description, pass data to the table and that's it. We used this table in our project for a couple of weeks. However, we needed editable cells, and we needed to select rows, so this table was too simple for us.

Another interesting table is the ng2-smart-table. Unfortunately, the fast pace of Angular updates breaks the project every once in a while. We didn't use it simply because it wasn't compatible with our version of Angular when we evaluated the table. Keep in mind that this is probably only a matter of time. Chances are the bug has been fixed when you read this article.

The grids of Kendo and Wijmo are almost certainly great choices, too. Too bad they are not available for free. So we chose to evaluate the other choices.

The documentation of the ngx-datatable lists several other alternatives. I didn't examine them, so suffice it to mention them: ng2-super-table, vaadin-grid, angular2-iron-data-table (which is built on a Polymer datatable) and another Material Design table, the paper-datatable.

Do you know any other table widget?

If you know a useful table widget I didn't mention, please leave a comment. I know you came here to learn something new, but it's just a minute of work. This article is one of the most popular articles of BeyondJava.net, so your contribution may help countless other developers!

Do it yourself (but don't do it from scratch)

The next option is to use one of the existing data tables and integrate them in an Angular application. I chose the table from DataTables.net, which is build on jQuery. That's a fine library we also use in the BootsFaces project. I could have chosen Chinese data table just as well. But I'm more familiar with DataTables.net.

There are several challenges to overcome: for instance, the Angular life-cycle isn't exactly compatible with the jQuery events. Adding insult to injury, the data table is available on NPM, but it seems to support Common.js, while the Angular CLI uses another module system.

By the way, if you don't use the Angular CLI, I recommend the article of

Mitch Talmadge, who integrates DataTables.net using Webpack.

Adding the dependencies to the package.json

Back to the Angular CLI approach. The first step is to install the dependencies:

npm install bootstrap --save npm install datatables.net --save npm install datatables.net-bs --save npm install datatables.net-select --save npm install datatables.net-select-bs --save npm install jquery --save npm install @types/jquery --save-dev

It's also a good idea to add types for the DataTable widget. As far as I can see, there are several type definition files. But there's no official type definition which is regularly maintained. This article simply casts the type to any. That's far from ideal, but it works. If you know a good type definition file, please leave a comment so I can improve this article.

Adding the files to the angular-cli.json

Next we add the CSS files to the angular-cli.json file:

"styles": [ "styles.css", "../node_modules/bootstrap/dist/css/bootstrap.min.css", "../node_modules/bootstrap/dist/css/bootstrap-theme.min.css", "../node_modules/datatables.net-bs/css/dataTables.bootstrap.css", "../node_modules/datatables.net-select-bs/css/select.bootstrap.css" ],

Creating the component

Now it's time to create the component for the data table using the command line command "ng g c datatable".

The HTML template file of the component is straight-forward, pretty much the way it's documented on the DataTables.net page:

First name Last name
{{row.name}}

This generates a table with a static cell and input fields in the second column.

TypeScript imports

The component class imports both jQuery and the Datatable like so:

import * as $ from 'jquery'; import 'datatables.net'

The second import statement circumvents the module system of TypeScript. It simply registers the DataTable as a jQuery plugin, which is fine by us.

Initializing the DataTables.net widget

The component initializes the data table in the ngAfterViewInit method. This relieves us from having to write an onDocumentLoad handler we'd use without Angular. Not a big deal, but still, it improves readability.

export class DatatableComponent implements OnInit { public tableWidget: any; ngAfterViewInit() { this.initDatatable() } private initDatatable(): void { let exampleId: any = $('#example'); this.tableWidget = exampleId.DataTable({ select: true }); } ... }

Adding and deleting rows

At first glance, the table already looks great. It's even possible to add or remove array elements, and the data table is redrawn. But there's a catch: sorting and filtering ignores the new rows.

So adding and deleting rows requires us to redraw the table. If you've got a simple table without input fields, it's possible to use the data object of the data table to add or delete rows. Unfortunately, the input field prevents that. I'm sure there's a better way, but I solved the problem by a brute-force approach: destroying and re-initializing the table does the trick. The disadvantage is that the table flickers. If you know how to do it better, please leave a comment. Until then, I'll show you the brute force approach:

private reInitDatatable(): void { if (this.tableWidget) { this.tableWidget.destroy() this.tableWidget=null } setTimeout(() => this.initDatatable(),0) } public deleteRow(): void { this.data.pop(); this.reInitDatatable() }

The timeout is needed to make sure that the data table is initialized after Angular has redrawn the page. Otherwise, you may end up with the message "no data" under a long table.

jQuery

Remains the question how to deal with jQuery events. By default, modifying attributes in a jQuery event listener doesn't trigger Angular's change detection. We can fix this using an event emitter:

@Output() rowSelected: EventEmitter = new EventEmitter(); private initDatatable(): void { let exampleId: any = $('#example'); this.tableWidget = exampleId.DataTable({ select: true }); this.tableWidget.on('select', (e, dt, type, indexes) => this.onRowSelect(indexes)) } private onRowSelect(indexes: number[]): void { this.rowSelected.emit(indexes[0]) }

For some reason, during my tests, the array indexes always contained a single number, no matter how many rows I'd selected. That's why the event emitter only broadcasts a single number instead of the entire array.

Using the component

After these preparations, using the data table is straight-forward:

export class AppComponent { public onRowSelected(index: number) { console.log(index) } }

Wrapping it up

This article has become a bit long, which may give you the impression integration a JavaScript data table library in an Angular application is difficult. In reality, it's pretty simple. The solution I presented is far from ideal, but it's good enough for most use cases, and it took me merely a couple of hours to implement it. Truth to tell, writing this article took more time than writing the actual code.

The extra value the full-blown Angular2 libraries give you is basically syntactical sugar (which is great!) and a better integration with the Angular life cycle. The trade-off is that these libraries are usually opinionated in one way or another.

Dig deeper

Source code of the demo on GitHub


Comments