Creating an Angular2 Datatable from Scratch

Some time ago I’ve posted a tutorial on how to create a datatable with ag-grid, it didn’t take long before people start complaining that ag-grid wasn’t working the way I described in the tutorial, that’s because angular2 is changing rapidly rendering the component and/or the tutorial obsolete.

Today I’m going to show you again how to create a datatable, but this time I’m going to do it without ag-grid or any other third-party component, this is how our component will look like after we’re done:

<datatable [dataset]=cities>
    <column [value]="'id'" [header]="'Id'"></column>
    <column [value]="'city'" [header]="'City'"></column>
    <column [value]="'country'" [header]="'Country'"></column>
</datatable>

That’s the simplest datatable structure I could come up with, as you can see we’re going to create two components: datatable and column.

Let’s take a look at the column component first:

import {Component, Input} from '@angular/core';
import {DatatableComponent} from './datatable.component';
 
@Component({
  selector: 'column',
  template: ``,
 
})
export class ColumnComponent {
	@Input() value;
	@Input() header;
 
	constructor(table: DatatableComponent) {
    	   table.addColumn(this)
  	}
}

This component has two attributes as inputs: value and header.

Value: This is the name of the attribute from your JSON dataset that will be displayed on this column (I’m going to talk about the dataset in a minute).
Header: As the name suggests, this is the column header text.

Besides these two attributes, there’s also the constructor, which very conveniently injects the DatatableComponent, allowing us to add this column to an array from the parent component. To fully understand why I’m doing this we have to take a look at the DatatableComponent:

import {Http, Response} from '@angular/http';
import {Injectable, Component, Input} from '@angular/core';
import {ColumnComponent} from './column.component';
 
@Component({
  selector: 'datatable',
  template: `<table>
               <thead>
                 <tr>
                   <th *ngFor="let column of columns">{{column.header}}</th>
                 </tr>
               </thead>
	       <tbody *ngFor="let row of dataset">
	  	 <tr>
	  	   <td *ngFor="let column of columns">{{row[column.value]}}</td>
	         </tr>
	       </tbody>
  	     </table>
  `
})
export class DatatableComponent { 
 
  @Input() dataset;
  columns: ColumnComponent[] = [];
 
  addColumn(column){
    this.columns.push(column);
  }
}

In this component we have the attribute dataset as an input (which will receive the JSON dataset) and the array of columns I just mentioned, each column will add itself to this array as we’ve seen on the ColumnComponent‘s constructor. In the template I’m iterating over both the dataset (rows) and the columns to create a regular HTML table.

After creating these two components we can use the datatable as I showed in the beginning, here is the app.component.ts:

import {Http, Response} from '@angular/http';
import {Injectable, Component } from '@angular/core';
 
@Component({
  selector: 'my-app',
  template: `<datatable [dataset]=cities>
                  <column [value]="'id'" [header]="'Id'"></column>
                  <column [value]="'city'" [header]="'City'"></column>
                  <column [value]="'country'" [header]="'Country'"></column>
             </datatable>
             `,
 
})
export class AppComponent { 
    cities;
 
    constructor(private http:Http) {
        this.http.get('data/cities.json')
                .subscribe(res => this.cities = res.json());
    }
}

Note that in the constructor I’m loading my dataset from the file cities.json, for more datails about that click here.

We’re almost done, the last thing we have to do is to declare our components in the app.module.ts:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule }      from '@angular/http';
import { AppComponent }   from './app.component';
import {DatatableComponent} from './datatable.component';
import {ColumnComponent} from './column.component';
 
@NgModule({
  imports:      [ BrowserModule, HttpModule ],
  declarations: [ AppComponent,DatatableComponent, ColumnComponent],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

That’s it for now guys! Click here to see the part 2 of this tutorial where I’m showing how to add the filter functionality, if you need other specific features please let me know in the comments, any suggestions are welcome!

Recommended for you

How to Load a JSON file in Angular2 Angular2 makes it very easy for us to load data from JSON files, we can do it by simply making a http request. Now let's see how we can do that. To be able to make Http requests we first have to import the HttpModule on the app.module.ts, once you've done that your code should look like this: ...
Angular2 error: Error in ./AppComponent class AppComponent_Host – inline template:0:0 caused b... If you're seeing this error when you run your application it's probably because you're trying to use http.get without importing the HttpModule. This is what the error looks like on the browser console: core.umd.js:5995 EXCEPTION: Error in ./AppComponent class AppComponent_Host - inline temp...
Angular2 Forms Tutorial: Validating Required Fields Angular2 Form Validation In this tutorial I'll give you a simple example of how to validate a form with angular2. As you can see in the image, the example consists of a form with two required fields, the form can only be submitted if both fields are valid. I'm going to use bootstrap for styli...
Creating an Angular2 Datatable from Scratch PART 2: Filtering the Data Continuing from where we stopped at Part 1, today we're going to add the filter functionality to the table, but before we start let's do some styling. I'm going to use Bootstrap, but if you don't want you don't have to, feel free to style your component as you like. But if you decide to use Bootstra...

12 comments on “Creating an Angular2 Datatable from Scratch

  1. Xin

    Hi, in the table component, for the line as below in the template

    {{row[column.value]}}

    what if I want to pass the row data to the column template component?

  2. Miguel Rico

    Hey this is awesome! and it works great! but I don’t really know…why/how it’s working.

    What is this process called? A component ‘swallowing’ another component like that?

    I didn’t even know you could pass a component through the constructor like that…man there is so much for me to learn!

    Thanks for posting this really helped out!! If you could help me out with my question just so I can go and educate my self, that would be great!

  3. Phuc

    Hi Leonardo,

    Thanks for sharing. I have 1 question about dynamic content template for columns. E.g: if column.value is a link or image source, I want to pass html link anchor or image …. how can I do that ?

    Thanks,

    1. pp

      this.cities = [
      {‘id':1,’city':”Berlin”,’country':”Germany”},
      {‘id':2,’city':”Amsterdam”,’country':”Netherlands”},
      {‘id':3,’city':”Paris”,’country':”France”},
      ]

  4. Dheeraj

    Thanks for sharing this info.
    One query like, how can we add functionality where I can only display 8 columns out of 30 columns in the UI and there is a more info like sign that user clicks to see other 22 columns added in the same existing table.

  5. bhavna

    Hi
    I am getting error after following your complete example like
    Unhandled Promise rejection: Template parse errors:
    Can’t bind to ‘dataset’ since it isn’t a known property of ‘datatable’. (“][dataset]=cities>

                      &lt;c&quot;): TableComponent@0:11
    Can&#039;t bind to &#039;value&#039; since it isn&#039;t a known property of &#039;column&#039;. (&quot;
              ][value]="'name'" [header]="'name'"&gt;
                      &lt;column [value]=&quot;&#039;state&#039;&quot; [header]=&quot;&#039;s&quot;): TableComponent@1:18
    Can&#039;t bind to &#039;header&#039; since it isn&#039;t a known property of &#039;column&#039;. (&quot;
              ][header]="'name'"&gt;
     
    "): TableComponent@1:35
    'column' is not a known element:
    1. If 'column' is an Angular component, then verify that it is part of this module.
    2. If 'column' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("
              [ERROR -&gt;]
     
     
                      ][value]="'state'" [header]="'state'"&gt;
     
                 "): TableComponent@2:26
    Can't bind to 'header' since it isn't a known property of 'column'. ("   
                      ][header]="'state'"&gt;
     
                 "): TableComponent@2:44
    'column' is not a known element:
    1. If 'column' is an Angular component, then verify that it is part of this module.
    2. If 'column' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. (" [dataset]=cities&gt;
     
                      [ERROR -&gt;]
     
                 "): TableComponent@2:18
    'datatable' is not a known element:
    1. If 'datatable' is an Angular component, then verify that it is part of this module.
    2. If 'datatable' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("[ERROR -&gt;]
     
             "): TableComponent@0:0 ; Zone:  ; Task: Promise.then ; Value: SyntaxError {__zone_symbol__error: Error: Template parse errors:
    Can't bind to 'dataset' since it isn't a known property of 'datatable'……} Error: Template parse errors:
    Can't bind to 'dataset' since it isn't a known property of 'datatable'. ("][dataset]=cities&gt;
     
                      &lt;c&quot;): TableComponent@0:11
    Can&#039;t bind to &#039;value&#039; since it isn&#039;t a known property of &#039;column&#039;. (&quot;
              ][value]="'name'" [header]="'name'"&gt;
                      &lt;column [value]=&quot;&#039;state&#039;&quot; [header]=&quot;&#039;s&quot;): TableComponent@1:18
    Can&#039;t bind to &#039;header&#039; since it isn&#039;t a known property of &#039;column&#039;. (&quot;
              ][header]="'name'"&gt;
     
    "): TableComponent@1:35
    'column' is not a known element:
    1. If 'column' is an Angular component, then verify that it is part of this module.
    2. If 'column' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("
              [ERROR -&gt;]
     
     
                      ][value]="'state'" [header]="'state'"&gt;
     
                 "): TableComponent@2:26
    Can't bind to 'header' since it isn't a known property of 'column'. ("   
                      ][header]="'state'"&gt;
     
                 "): TableComponent@2:44
    'column' is not a known element:
    1. If 'column' is an Angular component, then verify that it is part of this module.
    2. If 'column' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. (" [dataset]=cities&gt;
     
                      [ERROR -&gt;]
     
                 "): TableComponent@2:18
    'datatable' is not a known element:
    1. If 'datatable' is an Angular component, then verify that it is part of this module.
    2. If 'datatable' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("[ERROR -&gt;]
     
             "): TableComponent@0:0

Leave a Reply to Dheeraj Cancel reply

Your email address will not be published. Required fields are marked *

Obs: Use the tag <pre lang="LANGUAGE"> to include code blocks to your comment.
Example: <pre lang="javascript"> console.log('Test'); </pre>