Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use material2 data table

I am trying to implement Material2 data table. But I am not able to understand how to use it in proper way.

import {Component, ElementRef, ViewChild} 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 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/distinctUntilChanged'; import 'rxjs/add/observable/fromEvent';  @Component({   selector: 'table-filtering-example',   styleUrls: ['table-filtering-example.css'],   templateUrl: 'table-filtering-example.html', }) export class TableFilteringExample {   displayedColumns = ['userId', 'userName', 'progress', 'color'];   exampleDatabase = new ExampleDatabase();   dataSource: ExampleDataSource | null;    @ViewChild('filter') filter: ElementRef;    ngOnInit() {     this.dataSource = new ExampleDataSource(this.exampleDatabase);     Observable.fromEvent(this.filter.nativeElement, 'keyup')         .debounceTime(150)         .distinctUntilChanged()         .subscribe(() => {           if (!this.dataSource) { return; }           this.dataSource.filter = this.filter.nativeElement.value;         });   } }  /** Constants used to fill up our data base. */ 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'];  export interface UserData {   id: string;   name: string;   progress: string;   color: string; }  /** An example database that the data source uses to retrieve data for the table. */ export class ExampleDatabase {   /** Stream that emits whenever the data has been modified. */   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(); }   }    /** Adds a new user to the database. */   addUser() {     const copiedData = this.data.slice();     copiedData.push(this.createNewUser());     this.dataChange.next(copiedData);   }    /** Builds and returns a new User. */   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))]     };   } }  /**  * 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. It is not the data source's responsibility to manage  * the underlying data. Instead, it only needs to take the data and send the table exactly what  * should be rendered.  */ export class ExampleDataSource extends DataSource<any> {   _filterChange = new BehaviorSubject('');   get filter(): string { return this._filterChange.value; }   set filter(filter: string) { this._filterChange.next(filter); }    constructor(private _exampleDatabase: ExampleDatabase) {     super();   }    /** Connect function called by the table to retrieve one stream containing the data to render. */   connect(): Observable<UserData[]> {     const displayDataChanges = [       this._exampleDatabase.dataChange,       this._filterChange,     ];      return Observable.merge(...displayDataChanges).map(() => {       return this._exampleDatabase.data.slice().filter((item: UserData) => {         let searchStr = (item.name + item.color).toLowerCase();         return searchStr.indexOf(this.filter.toLowerCase()) != -1;       });     });   }    disconnect() {} } 

Above is the code of datatable that is very confusing for me. Even their documentation is very poor. Can someone explain what is the flow of above code?

Please ignore if you feel question is too basic to ask?

like image 969
Sunil Garg Avatar asked Jul 10 '17 05:07

Sunil Garg


People also ask

What is DataSource in mat-table?

A DataSource is simply a class that has at a minimum the following methods: connect and disconnect . The connect method will be called by the table to provide an Observable that emits the data array that should be rendered.

What is * MatHeaderCellDef?

MatHeaderCellDef extends CdkHeaderCellDefHeader cell definition for the mat-table. Captures the template of a column's header cell and as well as cell-specific properties. Selector: [matHeaderCellDef]


2 Answers

The code from your example is the definition for a generic table, using the new cdk component in the material2 specification. you must keep in mind the md-table is the visual implementation of the cdk-table, so you need to declare a cdk with a model compatible with the md-model in HTML.

For example:

I declare a cdk-table with following implementation:

  1. First, the dependencies:

The new CDK component in Material2, using:

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'; 
  1. Definition of the structure of the HTML in TS:

I define a displayedColumns array, the items are the columns in my HTML table, in order:

displayedColumns = ['userId', 'userName', 'progress']; 

A database of the type ExampleDatabase (an object with a manual definition particular):

exampleDatabase = new ExampleDatabase(); 

Finally, i declare a dataSource, this is the origin of my data. It is an object with a manual definition or data null.

dataSource: ExampleDataSource | null; 

In the ngOnInit() method, I simply declare that my dataSource is a new ExampleDataSource with parameter my exampleDataBase.

Good, now to implement the rest of the code:

First, declare an interface for the DataBase. This is very important for maintaining the congruence of the data, the database must respect a defined scheme. In this example, the database has three columns: id, name and progress:

export interface UserData {   id: number;   name: string;   progress: string; } 

The next point is create a class (Object) ExampleDatabase with the definition of the data in my DataBase. You could create a service for connecting to an actual database (PostgreSQL, MongoDB), get the real data and create the objects for the cdk-datatable in another method, however in this example we are using an in memory database emulated at run time.

export class ExampleDatabase {   /** Stream that emits whenever the data has been modified. */   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(); }   }    /** Adds a new user to the database. */   addUser() {     const copiedData = this.data.slice();     copiedData.push(this.createNewUser());     this.dataChange.next(copiedData);   }    /** Builds and returns a new User. */   private createNewUser() {      return {       id: 1,       name: 'example',       progress: Math.round(Math.random() * 100).toString()     };   } } 

Good, finally i create a second class with the definition of my DataSource.

export class ExampleDataSource extends DataSource<any> {   constructor(private _exampleDatabase: ExampleDatabase) {     super();   }    /** Connect function called by the table to retrieve one stream containing the data to render. */   connect(): Observable<UserData[]> {     return this._exampleDatabase.dataChange;   }    disconnect() { } } 

This method makes sure the data is in the correct format, and releases the "connection" to the DataBase (in memory) to get the data in it.

Finally, use the md-table component or cdk-table component in the HTML. The md-table component uses the material design style, and the cdk-table uses a generic style..

md-table:

<div class="example-container mat-elevation-z8">   <md-table #table [dataSource]="dataSource">      <!-- ID Column -->     <ng-container cdkColumnDef="userId">       <md-header-cell *cdkHeaderCellDef> ID </md-header-cell>       <md-cell *cdkCellDef="let row"> {{row.id}} </md-cell>     </ng-container>      <!-- Progress Column -->     <ng-container cdkColumnDef="progress">       <md-header-cell *cdkHeaderCellDef> Progress </md-header-cell>       <md-cell *cdkCellDef="let row"> {{row.progress}}% </md-cell>     </ng-container>      <!-- Name Column -->     <ng-container cdkColumnDef="userName">       <md-header-cell *cdkHeaderCellDef> Name </md-header-cell>       <md-cell *cdkCellDef="let row"> {{row.name}} </md-cell>     </ng-container>      <md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>     <md-row *cdkRowDef="let row; columns: displayedColumns;"></md-row>   </md-table> </div> 

cdk-table:

<div class="example-container mat-elevation-z8">   <cdk-table #table [dataSource]="dataSource" class="example-table">      <!-- ID Column -->     <ng-container cdkColumnDef="userId">       <cdk-header-cell *cdkHeaderCellDef class="example-header-cell"> ID </cdk-header-cell>       <cdk-cell *cdkCellDef="let row" class="example-cell"> {{row.id}} </cdk-cell>     </ng-container>      <!-- Progress Column -->     <ng-container cdkColumnDef="progress">       <cdk-header-cell *cdkHeaderCellDef class="example-header-cell"> Progress </cdk-header-cell>       <cdk-cell *cdkCellDef="let row" class="example-cell"> {{row.progress}}% </cdk-cell>     </ng-container>      <!-- Name Column -->     <ng-container cdkColumnDef="userName">       <cdk-header-cell *cdkHeaderCellDef class="example-header-cell"> Name </cdk-header-cell>       <cdk-cell *cdkCellDef="let row" class="example-cell"> {{row.name}} </cdk-cell>     </ng-container>      <cdk-header-row *cdkHeaderRowDef="displayedColumns" class="example-header-row"></cdk-header-row>     <cdk-row *cdkRowDef="let row; columns: displayedColumns;" class="example-row"></cdk-row>   </cdk-table> </div> 

The rest of implementations, search, menus, checkboxes, etc, is your responsibility to implement the logic for manipulating the information.

Use the documentation about cdk-table for more details:

https://material.angular.io/guide/cdk-table

Result:

enter image description here

Do me saber and achievement, I understand my explanation, and I apologize for my English. I am learning.

like image 196
Ata Sanchez Avatar answered Oct 11 '22 20:10

Ata Sanchez


Here is the customized code created for view attendance, right now i have hard coded the data , you can call service instead of that for getting dynamic data.

app.component.ts

import { Component, OnInit, ElementRef, ViewEncapsulation, ViewChild } from '@angular/core'; import { DataSource } from '@angular/cdk'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Observable } from 'rxjs/Observable'; import { MdPaginator, MdSort } from '@angular/material'; import 'rxjs/add/operator/startWith'; import 'rxjs/add/observable/merge'; import 'rxjs/add/operator/map'; declare let d3: any;  @Component({   selector: 'app-root',   templateUrl: './app.component.html',   styleUrls: ['./app.component.css'] })   export class AppComponent implements OnInit {    displayedColumns = ['shiftDate', 'swipeIn', 'swipeOut', 'duration', 'status'];   exampleDatabase = new ExampleDatabase();   dataSource: ExampleDataSource | null;    @ViewChild(MdPaginator) paginator: MdPaginator;   @ViewChild(MdSort) sort: MdSort;    ngOnInit() {     this.dataSource = new ExampleDataSource(this.exampleDatabase, this.paginator, this.sort);   } }  export interface attendanceData {   shiftDate: string;   swipeIn: string;   swipeOut: string;   duration: string;   status: string; }   /** An example database that the data source uses to retrieve data for the table. */ export class ExampleDatabase {   /** Stream that emits whenever the data has been modified. */   dataChange: BehaviorSubject<attendanceData[]> = new BehaviorSubject<attendanceData[]>([]);   get data(): attendanceData[] {      let data = [       {         "shiftDate": "17-July-2017",         "swipeIn": "10:00 AM",         "swipeOut": "06:00 PM",         "duration": "8 Hours",         "status": "PRESENT"        },       {         "shiftDate": "16-July-2017",         "swipeIn": "9:00 AM",         "swipeOut": "5:00 AM",         "duration": "7 Hours",         "status": "PRESENT"       }      ];      return data;   }    constructor() {      this.dataChange.next(this.data);   }  }  export class ExampleDataSource extends DataSource<any> {   _filterChange = new BehaviorSubject('');   get filter(): string { return this._filterChange.value; }   set filter(filter: string) { this._filterChange.next(filter); }    constructor(private _exampleDatabase: ExampleDatabase, private _paginator: MdPaginator, private _sort: MdSort) {     super();   }    /** Connect function called by the table to retrieve one stream containing the data to render. */   connect(): Observable<attendanceData[]> {     const displayDataChanges = [       this._exampleDatabase.dataChange,       this._paginator.page,       this._sort.mdSortChange     ];      return Observable.merge(...displayDataChanges).map(() => {       // const data = this._exampleDatabase.data.slice();       const data = this.getSortedData();       // Grab the page's slice of data.       const startIndex = this._paginator.pageIndex * this._paginator.pageSize;       return data.splice(startIndex, this._paginator.pageSize);     });   }    disconnect() { }    getSortedData(): attendanceData[] {     const data = this._exampleDatabase.data.slice();     if (!this._sort.active || this._sort.direction == '') { return data; }      return data.sort((a, b) => {       let propertyA: number | string = '';       let propertyB: number | string = '';        switch (this._sort.active) {         case 'shiftDate': [propertyA, propertyB] = [a.shiftDate, b.shiftDate]; break;         case 'swipeIn': [propertyA, propertyB] = [a.swipeIn, b.swipeIn]; break;         case 'swipeOut': [propertyA, propertyB] = [a.swipeOut, b.swipeOut]; break;         case 'duration': [propertyA, propertyB] = [a.duration, b.duration]; break;       }        let valueA = isNaN(+propertyA) ? propertyA : +propertyA;       let valueB = isNaN(+propertyB) ? propertyB : +propertyB;        return (valueA < valueB ? -1 : 1) * (this._sort.direction == 'asc' ? 1 : -1);     });   } } 

app.component.html

<div class="example-container mat-elevation-z8">   <md-table #table [dataSource]="dataSource" mdSort>     <!--- Note that these columns can be defined in any order.           The actual rendered columns are set as a property on the row definition" -->      <!-- ID Column -->     <ng-container cdkColumnDef="shiftDate">       <md-header-cell *cdkHeaderCellDef md-sort-header> Shift Date </md-header-cell>       <md-cell *cdkCellDef="let row"> {{row.shiftDate}} </md-cell>     </ng-container>      <!-- Progress Column -->     <ng-container cdkColumnDef="swipeIn">       <md-header-cell *cdkHeaderCellDef md-sort-header> Swipe In </md-header-cell>       <md-cell *cdkCellDef="let row"> {{row.swipeIn}}% </md-cell>     </ng-container>      <!-- Name Column -->     <ng-container cdkColumnDef="swipeOut">       <md-header-cell *cdkHeaderCellDef> Swipe Out </md-header-cell>       <md-cell *cdkCellDef="let row"> {{row.swipeOut}} </md-cell>     </ng-container>      <!-- Color Column -->     <ng-container cdkColumnDef="duration">       <md-header-cell *cdkHeaderCellDef>Duration</md-header-cell>       <md-cell *cdkCellDef="let row"> {{row.duration}} </md-cell>     </ng-container>       <!-- Color Column -->     <ng-container cdkColumnDef="status">       <md-header-cell *cdkHeaderCellDef>Status</md-header-cell>       <md-cell *cdkCellDef="let row"> {{row.status}} </md-cell>     </ng-container>      <md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>     <md-row *cdkRowDef="let row; columns: displayedColumns;"></md-row>   </md-table>      <md-paginator #paginator                 [length]="exampleDatabase.data.length"                 [pageIndex]="0"                 [pageSize]="25"                 [pageSizeOptions]="[5, 10, 25, 100]">   </md-paginator>  </div> 

app.module.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NgModule } from '@angular/core'; import { MaterialModule, MdTableModule  } from '@angular/material'; import { FlexLayoutModule } from '@angular/flex-layout'; import { CdkTableModule } from '@angular/cdk';   import { AppComponent } from './app.component';    @NgModule({   declarations: [     AppComponent,   ],   imports: [     BrowserAnimationsModule,     CdkTableModule,     BrowserModule,     MaterialModule, MdTableModule,     FlexLayoutModule   ],   providers: [],   bootstrap: [AppComponent] }) export class AppModule { } 
like image 44
Shijith Mohanan Avatar answered Oct 11 '22 20:10

Shijith Mohanan