Here is an article written by me.you will find everything you need to know in here.
https://medium.com/@fnote/md-tables-angular-material-be2c45947955
lets take the code piece by piece.you will find the complete code here https://material.angular.io/components/table/overview
import {Component} from '@angular/core';
import {DataSource} from '@angular/cdk';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';
import the necessary packages you require. Make sure you install angular cdk while you are installing angular material.
Before proceeding it is better to mention what is a data source what is an observable and what is a behavior subject and also rxjs.
RXJS is a hot topic in frond end development these days .It is a javascript library for reactive programming ( Reactive programming is just a way of building software applications. Essentially, your software is built to “react” to changes that happen (like click events, data being fetched, etc)) using Observables, to make it easier to compose asynchronous or callback-based code.
cdk is imported because md-tables are built on top of it. Cdk tables are the foundation to md tables.
What is an observable?
The ability of observables being able to handle multiple values over time makes them a good candidate for working with real-time data, events and any sort of stream you can think of.
Observables gives better control when working with in-flow of values from a stream.
Observable is a wrapper around a datasource , data source is a stream of values possibly emits multiple values over time we want to do something whenever a new value occurs.
We connect observer and observable through a subscription. Subscription says there is someone listening to these stream of values.
An observer subscribes to an Observable. An Observable emits items or sends notifications to its observers by calling the observers’ methods.
observer implements up to 3 methods.they are complete() ,next() and onerror().
next() method will be called by the observable whenever a new value is emitted.whenever observable throws an error onerror() method is invoked.when observable is done and when it knows there won’t be any more new values in the future it calls complete() method.
I strongly recommend you follow the series by academind on youtube about RXJS library to get a deeper understanding about RXJS capabilities, observers, observables, subjects, behavior subjects and subscriptions.
Let’s continue with the code
@Component({
selector: 'table-basic-example',
styleUrls: ['table-basic-example.css'],
templateUrl: 'table-basic-example.html',
})
This is regular angular 4.selector is the name by which outside parties refer to our component .and style Url is the location our /file this component refer for styling purposes and basic html of the component is found in the template url.
export class TableBasicExample {
displayedColumns = ['userId', 'userName', 'progress', 'color'];
exampleDatabase = new ExampleDatabase();
dataSource: ExampleDataSource | null;
ngOnInit() {
this.dataSource = new ExampleDataSource(this.exampleDatabase);
}
}
Here first we make an array of all the columns of our table we need to display on the browser (column headings ) this array is referred again from the html file.
And further we create an instance of example database class and an instance of datasource which carries no data at the beginning.
Then the data in the example database is injected to this datasource to fill it as it is initially empty
Ng onitint is a life cycle hook that is called by angular in order to mark the completion of creation of the component.
const COLORS = ['maroon', 'red', 'orange', 'yellow', 'olive', 'green',
'purple','fuchsia', 'lime', 'teal', 'aqua', 'blue', 'navy', 'black',
'gray'];
const NAMES = ['Maia', 'Asher', 'Olivia', 'Atticus', 'Amelia',
'Jack','Charlotte', 'Theodore', 'Isla', 'Oliver', 'Isabella',
'Jasper','Cora', 'Levi', 'Violet', 'Arthur', 'Mia', 'Thomas', 'Elizabeth'];
The we have 2 arrays .these fill up our example database
export interface UserData {
id: string;
name: string;
progress: string;
color: string;
}
Here you have an interface defined. The variables mentioned here will eventually become the columns of our tables.
export class ExampleDatabase {
dataChange: BehaviorSubject<UserData[]> = new BehaviorSubject<UserData[]>
([]);
get data(): UserData[] { return this.dataChange.value; }
constructor() {
// Fill up the database with 100 users.
for (let i = 0; i < 100; i++) { this.addUser(); }
}
addUser() {
const copiedData = this.data.slice();
copiedData.push(this.createNewUser());
this.dataChange.next(copiedData);
}
private createNewUser() {
const name =
NAMES[Math.round(Math.random() * (NAMES.length - 1))] + ' ' +
NAMES[Math.round(Math.random() * (NAMES.length - 1))].charAt(0) + '.';
return {
id: (this.data.length + 1).toString(),
name: name,
progress: Math.round(Math.random() * 100).toString(),
color: COLORS[Math.round(Math.random() * (COLORS.length - 1))]
};
}
}
This is the example database that the datasource uses to retrieve data for the table. You only have 2 arrays defined but in fact 4 columns to be displayed. You can fill 2 columns from the data in the arrays but the data for the other 2 columns here must be generated inside this class.
So what is a subject?
Observable can’t emit values itself but we want to be able to do it ourselves .but if we need to emit new values ourselves we have to go with a subject. Subject is an observable it inherits from observable but we can call the next() method on it manually do that we can trigger a emitting of a new value. Therefore subject is an active observable. It is an observer in addition to being an observable so you can also send values to a subject in addition to subscribing to it.
What in the world is a behavior subject?
Behavior subject is a special kind of a subject but it has an initial value unlike subjects. It needs an initial value as it must always return a value on subscription even if it hasn’t received a next()
Rx.subject()
subscription won’t get anything initially
Rx.behaviorsubject(‘a’)
subscription get ‘a’ initially
Don’t worry about the code written with const name…we have about 20 names in the names array but we need 100 distinct names.So here we change their initials in a random pattern.
Progress is also calculated randomly.
Data change is a variable of type behavior subject.
this.dataChange.next(copiedData);
..whenever a new user gets pushed in to the array that datachange is notified to the subscribers. Datachange is a sort of a Stream that emits whenever the data has been modified.
Make a variable called datachange that is a behavior subject that has an array of initial values
Make an array called copied data
Create a new user with 4 properties. Users are created like objects here with these 4 properties being their attributes.
Call the next method with the new user added
Call the next method on the special observable and subject emits.add user() adds a user to the database while create user method builds a user object with 4 distinct attributes.
Data source to provide what data should be rendered in the table. Note that the data source can retrieve its data in any way. In this case, the data source is provided a reference to a common data base, ExampleDatabase. Datasource only take the data and send the table exactly what should be rendered, nothing else.
export class ExampleDataSource extends DataSource<any> {
constructor(private _exampleDatabase: ExampleDatabase) {
super();
}
connect(): Observable<UserData[]> {
return this._exampleDatabase.dataChange;
}
disconnect() {}
}
Connecting the table to data source
Data is provided to the table through a DataSource.
Connect function connects a collection viewer such as a data table to a datasource. Connect function is called by the table to get the stream containing the data that should be rendered. Parameters has to be given to this connect function.
When the table receives a data source, it calls the DataSource’s connect function which returns an observable that emits an array of data.
Whenever the data source emits data to this stream, the table will update.
Because the data source provides this stream, it bears the responsibility of triggering table updates. This can be based on anything: web socket connections, user interaction, model updates, time-based intervals, etc. Most commonly, updates will be triggered by user interactions like sorting and pagination.
Disconnect function breaks the connection between the table and the datasource.
Lets look at the HTML file or our template.
Cell templates
<ng-container cdkColumnDef="color">
<md-header-cell *cdkHeaderCellDef>Color</md-header-cell>
<md-cell *cdkCellDef="let row" [style.color]="row.color"> {{row.color}}
</md-cell>
</ng-container>
Firstly columns of the table are defined.with the directive cdkColumnDef each column is given a name.this is the name from which this particular column in the table is referred from other places.each column then goes on to define a header cell template and a data cell template.header cell provides and displays the name of the column and cell template retrieves data that should be displayed and displays them below the header in rows.
cdkCellDef exports row context
tables header row and data row are defined below
Row Templates are given below,
<md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
<md-row *cdkRowDef="let row; columns: displayedColumns;"></md-row>
‘Displayed columns’ array is in your .ts (typescript file) and color is a column or an element of the array (as per our example).
These row templates looks at the name given to the cdkColumnDef and finds the specific columns to render.
The cdkRowDef also exports row context. Rendered content of the row comes from the cell templates not from the row templates.
For further reading on this check this out
Angular Material
Edit description
material.angular.io
how to generate required Columns dynamically ?
<ng-container *ngFor="let col of displayedColumns" cdkColumnDef= {{col}}>
<md-header-cell *cdkHeaderCellDef md-sort-header > {{ col }} </md-header-
cell>
<md-cell *cdkCellDef="let row"> {{row[col]}} </md-cell>
</ng-container>
compare this piece of code with the one before the last .here we loop through the displayedColumns array and column names are assigned in the process therefore we generate required columns looping through the array instead of defining all required columns by hand in the HTML file.
With this I will conclude this explanation, md tables further offers you features like pagination, sorting and filtering. The official documentation includes examples that you can refer to in order to add these features to your md table.
Now you know what happens behind the scenes in a md table.