Categories
Angular Material

Angular Material — Tooltips and Tree Display

Angular Material is a popular UI framework based on Material Design for Angular.

In this article, we’ll look at how to use Angular Material into our Angular project.

Tooltips

We can add tooltips with Angular Material.

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatButtonModule } from '@angular/material/button';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatTooltipModule,
    MatButtonModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.html

<div class="example-container" cdkScrollable>
  <button mat-raised-button #tooltip="matTooltip"
    matTooltip="Info about the action" matTooltipPosition="below"
    matTooltipHideDelay="100000"
    class="example-button">
    Action
  </button>
</div>

We add the tooltip by adding the matTooltip directive to the button.

matTooltipHideDelay sets the delay to hide the tooltip.

matTooltipPosition sets the position of the tooltip. Its value can be 'below' , 'above' , 'left' or 'right' .

Tooltip Class

We can set the tooltip class with the matTooltipClass attribute.

For example, we can write:

app.component.html

<div class="example-container" cdkScrollable>
  <button mat-raised-button #tooltip="matTooltip"
    matTooltip="Info about the action" matTooltipPosition="below"
    matTooltipClass="example-tooltip-red" matTooltipHideDelay="100000"
    class="example-button">
    Action
  </button>
</div>

styles.css

.example-button {
  margin-top: 16px;
}

.example-tooltip-red {
  background: #b71c1c;
}

We add the matTooltipClass attribute and set the styles for the tooltip in styles.css .

Tree

The mat-tree component lets us add a tree display to our app.

For example, we can write:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatTreeModule } from '@angular/material/tree';
import { MatButtonModule } from '@angular/material/button';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatTreeModule,
    MatButtonModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { FlatTreeControl } from '@angular/cdk/tree';
import { Component } from '@angular/core';
import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';

interface FoodNode {
  name: string;
  children?: FoodNode[];
}

const TREE_DATA: FoodNode[] = [
  {
    name: 'Fruit',
    children: [
      { name: 'Apple' },
      { name: 'Banana' },
      { name: 'Fruit loops' },
    ]
  }, {
    name: 'Vegetables',
    children: [
      {
        name: 'Green',
        children: [
          { name: 'Broccoli' },
          { name: 'Brussels sprouts' },
        ]
      }, {
        name: 'Orange',
        children: [
          { name: 'Pumpkins' },
          { name: 'Carrots' },
        ]
      },
    ]
  },
];

interface ExampleFlatNode {
  expandable: boolean;
  name: string;
  level: number;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  private _transformer = (node: FoodNode, level: number) => {
    return {
      expandable: !!node.children && node.children.length > 0,
      name: node.name,
      level: level,
    };
  }

  treeControl = new FlatTreeControl<ExampleFlatNode>(
    node => node.level, node => node.expandable);

  treeFlattener = new MatTreeFlattener(
    this._transformer, node => node.level, node => node.expandable, node => node.children);

  dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);

  constructor() {
    this.dataSource.data = TREE_DATA;
  }

  hasChild = (_: number, node: ExampleFlatNode) => node.expandable;
}

app.component.html

<div>
  <mat-tree [dataSource]="dataSource" [treeControl]="treeControl">
    <mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding>
      <button mat-icon-button disabled></button>
      {{node.name}}
    </mat-tree-node>
    <mat-tree-node *matTreeNodeDef="let node; when: hasChild" matTreeNodePadding>
      <button mat-icon-button matTreeNodeToggle
        [attr.aria-label]="'Toggle ' + node.name">
        <mat-icon class="mat-icon-rtl-mirror">
          {{treeControl.isExpanded(node) ? '&#8595;' : '&#8594;'}}
        </mat-icon>
      </button>
      {{node.name}}
    </mat-tree-node>
  </mat-tree>

</div>

We add the MatTreeModule to let us add the tree display.

And the MatButtonModule lets us add the button for the tree nodes.

In app.component.ts , we add the treeControl variable that we use with the treeControl directive to bind to the mat-tree .

This way, we can manipulate the tree.

dataSource is created from the MatTreeDataSource constructor.

We also need the hasChild method to let Angular Material check if there are any child nodes in the tree.

In the button, we check is the node is expanded with the treeControl.isExpanded method.

Then we can change the tree node display accordingly.

Conclusion

We can add tooltips and a tree display with Angular Material.

Categories
Angular Material

Angular Material — Tabs and Toolbars

Angular Material is a popular UI framework based on Material Design for Angular.

In this article, we’ll look at how to use Angular Material into our Angular project.

Tabs

We can add tabs with Angular Material.

To add it, we can write:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatTabsModule } from '@angular/material/tabs';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatTabsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.html

<div>
  <mat-tab-group mat-align-tabs="start">
    <mat-tab label="First">Content 1</mat-tab>
    <mat-tab label="Second">Content 2</mat-tab>
    <mat-tab label="Third">Content 3</mat-tab>
  </mat-tab-group>
</div>

We add the MatTabsModule into our Angular module.

Then we add the mat-tab-group and the mat-tab component to add the tabs.

The label has the tab header text.

The content between the mat-tab tags are the tab content.

The mat-align-tabs attribute lets us align the tabs to the position we want.

Other values of it can be center or end .

Toolbar

We can add a toolbar with the mat-toolbar component.

For instance, we can write:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatToolbarModule,
    MatIconModule,
    MatButtonModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.html

<div>
  <mat-toolbar>
    <button mat-icon-button class="example-icon"
      aria-label="Example icon-button with menu icon">
      <mat-icon>menu</mat-icon>
    </button>
    <span>My App</span>
    <span class="example-spacer"></span>
    <button mat-icon-button class="example-icon favorite-icon"
      aria-label="Example icon-button with heart icon">
      <mat-icon>favorite</mat-icon>
    </button>
    <button mat-icon-button class="example-icon"
      aria-label="Example icon-button with share icon">
      <mat-icon>share</mat-icon>
    </button>
  </mat-toolbar>
</div>

styles.css

.example-spacer {
  flex: 1 1 auto;
}

We add the MatIconModule , MatToolbarModule , and MatButtonModule to let us add the toolbar button icons, toolbar, and buttons respectively.

In app.component.html , we add the toolbar with the mat-toolbar component.

The mat-icon-button directive lets us add icon buttons.

In styles.css , we add the flex property to let us space out the buttons.

We can add a multi-row toolbar with:

app.component.html

<div>
  <mat-toolbar color="primary">
    <mat-toolbar-row>
      <span>Custom Toolbar</span>
    </mat-toolbar-row>

    <mat-toolbar-row>
      <span>Second Line</span>
      <span class="example-spacer"></span>
      <mat-icon class="example-icon" aria-hidden="false"
        aria-label="Example user verified icon">verified_user</mat-icon>
    </mat-toolbar-row>

    <mat-toolbar-row>
      <span>Third Line</span>
      <span class="example-spacer"></span>
      <mat-icon class="example-icon" aria-hidden="false"
        aria-label="Example heart icon">favorite</mat-icon>
      <mat-icon class="example-icon" aria-hidden="false"
        aria-label="Example delete icon">delete</mat-icon>
    </mat-toolbar-row>
  </mat-toolbar>
</div>

We add the mat-toolbar-row component into our mat-toolbar component to add the rows.

Conclusion

We can add tabs and toolbars easily with Angular Material.

Categories
Angular Material

Angular Material — Tables with Sorting, Filtering, and Pagination

Angular Material is a popular UI framework based on Material Design for Angular.

In this article, we’ll look at how to use Angular Material into our Angular project.

Table with Filtering

We can add an input box to let us search the table.

For example, we can write:

app.component.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatTableModule } from '@angular/material/table';
import { MatInputModule } from '@angular/material/input';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatTableModule,
    MatInputModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

styles.css

table {
  width: 100%;
}

app.component.ts

import { Component } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';

export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

const ELEMENT_DATA: PeriodicElement[] = [
  { position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' },
  { position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' },
  { position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li' },
  { position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be' },
  { position: 5, name: 'Boron', weight: 10.811, symbol: 'B' },
];

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = new MatTableDataSource(ELEMENT_DATA);

  applyFilter(event: Event) {
    const filterValue = (event.target as HTMLInputElement).value;
    this.dataSource.filter = filterValue.trim().toLowerCase();
  }
}

app.component.html

<div>
  <mat-form-field>
    <mat-label>Filter</mat-label>
    <input matInput (keyup)="applyFilter($event)" placeholder="Element" #input>
  </mat-form-field>

  <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
    <ng-container matColumnDef="position">
      <th mat-header-cell *matHeaderCellDef> No. </th>
      <td mat-cell *matCellDef="let element"> {{element.position}} </td>
    </ng-container>

    <ng-container matColumnDef="name">
      <th mat-header-cell *matHeaderCellDef> Name </th>
      <td mat-cell *matCellDef="let element"> {{element.name}} </td>
    </ng-container>

    <ng-container matColumnDef="weight">
      <th mat-header-cell *matHeaderCellDef> Weight </th>
      <td mat-cell *matCellDef="let element"> {{element.weight}} </td>
    </ng-container>

    <ng-container matColumnDef="symbol">
      <th mat-header-cell *matHeaderCellDef> Symbol </th>
      <td mat-cell *matCellDef="let element"> {{element.symbol}} </td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>

    <tr class="mat-row" *matNoDataRow>
      <td class="mat-cell" colspan="4">No data matching the filter
        "{{input.value}}"</td>
    </tr>
  </table>
</div>

We add the MatTableModule to let us add the table with Material Design style.

MatInputModule lets us add the input box.

In app.component.ts , we added the applyFilter method to let us filter the items by setting the this.dataSource.filter method.

Then we add the table element with the input box that runs applyFilter to let us filter the items.

Sorting and Pagination

We can add sorting and pagination to our table.

For example, we can write:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatTableModule } from '@angular/material/table';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatTableModule,
    MatPaginatorModule,
    MatSortModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component, ViewChild } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';

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

const COLORS: string[] = [
  'maroon', 'red', 'orange', 'yellow', 'olive', 'green'
];
const NAMES: string[] = [
  'Maia', 'Asher', 'Olivia', 'Atticus', 'Amelia', 'Jack'
];

const createNewUser = (id: number): UserData => {
  const name = `${NAMES[Math.round(Math.random() * (NAMES.length - 1))]} ${NAMES[Math.round(Math.random() * (NAMES.length - 1))].charAt(0)}`;
  return {
    id: id.toString(),
    name: name,
    progress: Math.round(Math.random() * 100).toString(),
    color: COLORS[Math.round(Math.random() * (COLORS.length - 1))]
  };
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  displayedColumns: string[] = ['id', 'name', 'progress', 'color'];
  dataSource: MatTableDataSource<UserData>;

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  constructor() {
    const users = Array.from({ length: 100 }, (_, k) => createNewUser(k + 1));
    this.dataSource = new MatTableDataSource(users);
  }

  ngAfterViewInit() {
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  }
}

app.component.html

<div>
  <div class="mat-elevation-z8">
    <table mat-table [dataSource]="dataSource" matSort>
      <ng-container matColumnDef="id">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> ID </th>
        <td mat-cell *matCellDef="let row"> {{row.id}} </td>
      </ng-container>

      <ng-container matColumnDef="progress">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Progress </th>
        <td mat-cell *matCellDef="let row"> {{row.progress}}% </td>
      </ng-container>

      <ng-container matColumnDef="name">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
        <td mat-cell *matCellDef="let row"> {{row.name}} </td>
      </ng-container>

      <ng-container matColumnDef="color">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Color </th>
        <td mat-cell *matCellDef="let row" [style.color]="row.color">
          {{row.color}} </td>
      </ng-container>

      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>

      <tr class="mat-row" *matNoDataRow>
        <td class="mat-cell" colspan="4">No data matching the filter
          "{{input.value}}"</td>
      </tr>
    </table>

    <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
  </div>
</div>

styles.css

table {
  width: 100%;
}

We add the MatSortModule to let us add sorting for the columns.

MatPaginatorModule adds the paginator control to let us move through the pages and select the page size.

We create the entries for the table in app.component.ts with the createNewUser function.

In the AppComponent class, we just create the data source and set it as the dataSource with the MatTableDataSource constructor.

And we set the paginator and sort properties to the paginator and sort components that we added.

The matSort directive lets us add sorting to the table.

And the mat-sort-header lets us enable sorting to the column header cells.

The mat-paginator component is added at the bottom to let us show the pagination controls

Conclusion

We can add tables with sorting, filtering, and pagination with Angular Material.

Categories
Angular Material

Angular Material — Tables

Angular Material is a popular UI framework based on Material Design for Angular.

In this article, we’ll look at how to use Angular Material into our Angular project.

Tables

We can add a table with Material Design style with Angular Material.

For example, we can write:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatTableModule } from '@angular/material/table';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatTableModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component } from '@angular/core';

export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

const ELEMENT_DATA: PeriodicElement[] = [
  { position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' },
  { position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' },
  { position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li' },
  { position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be' },
  { position: 5, name: 'Boron', weight: 10.811, symbol: 'B' },
];

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = ELEMENT_DATA;
}

app.component.html

<div>
  <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
    <ng-container matColumnDef="position">
      <th mat-header-cell *matHeaderCellDef> No. </th>
      <td mat-cell *matCellDef="let element"> {{element.position}} </td>
    </ng-container>

    <ng-container matColumnDef="name">
      <th mat-header-cell *matHeaderCellDef> Name </th>
      <td mat-cell *matCellDef="let element"> {{element.name}} </td>
    </ng-container>

    <ng-container matColumnDef="weight">
      <th mat-header-cell *matHeaderCellDef> Weight </th>
      <td mat-cell *matCellDef="let element"> {{element.weight}} </td>
    </ng-container>

    <ng-container matColumnDef="symbol">
      <th mat-header-cell *matHeaderCellDef> Symbol </th>
      <td mat-cell *matCellDef="let element"> {{element.symbol}} </td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
  </table>
</div>

styles.css

table {
    width: 100%;
}

We add the MatTableModule to add the table.

Then in app.component.ts , we add the table data in the ELEMENT_DATA array.

The displayColumns array has the column names.

In app.component.html , we add the mat-table directive to make the table Material Design style.

dataSource has the data table’s data source.

The ng-container components have the column definitions.

matColumnDef have the columns.

The th and td are in the ng-container and they’ll be shown in the table.

In styles.css , we set the width to 100% to make the table fill the screen.

Expandable Rows

We can add expandable rows into our table.

For example, we can write:

app.component.ts

import { Component } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';

export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

const ELEMENT_DATA: PeriodicElement[] = [
  { position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' },
  { position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' },
  { position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li' },
  { position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be' },
  { position: 5, name: 'Boron', weight: 10.811, symbol: 'B' },
];

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  animations: [
    trigger('detailExpand', [
      state('collapsed', style({ height: '0px', minHeight: '0' })),
      state('expanded', style({ height: '*' })),
      transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
    ]),
  ],
})
export class AppComponent {
  dataSource = ELEMENT_DATA;
  columnsToDisplay = ['name', 'weight', 'symbol', 'position'];
  expandedElement: PeriodicElement | null;
}

styles.css

table {
  width: 100%;
}

tr.example-detail-row {
  height: 0 !important;
}

tr.example-element-row:not(.example-expanded-row):hover {
  background: whitesmoke;
}

tr.example-element-row:not(.example-expanded-row):active {
  background: #efefef;
}

.example-element-row td {
  border-bottom-width: 0;
}

.example-element-detail {
  overflow: hidden;
  display: flex;
}

.example-element-diagram {
  min-width: 80px;
  border: 2px solid black;
  padding: 8px;
  font-weight: lighter;
  margin: 8px 0;
  height: 104px;
}

.example-element-symbol {
  font-weight: bold;
  font-size: 40px;
  line-height: normal;
}

.example-element-description {
  padding: 16px;
}

.example-element-description-attribution {
  opacity: 0.5;
}

app.component.html

<div>
  <table mat-table [dataSource]="dataSource" multiTemplateDataRows
    class="mat-elevation-z8">
    <ng-container matColumnDef="{{column}}"
      *ngFor="let column of columnsToDisplay">
      <th mat-header-cell *matHeaderCellDef> {{column}} </th>
      <td mat-cell *matCellDef="let element"> {{element[column]}} </td>
    </ng-container>

    <ng-container matColumnDef="expandedDetail">
      <td mat-cell *matCellDef="let element"
        [attr.colspan]="columnsToDisplay.length">
        <div class="example-element-detail"
          [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
          <div class="example-element-diagram">
            <div class="example-element-position"> {{element.position}} </div>
            <div class="example-element-symbol"> {{element.symbol}} </div>
            <div class="example-element-name"> {{element.name}} </div>
            <div class="example-element-weight"> {{element.weight}} </div>
          </div>
        </div>
      </td>
    </ng-container>

  <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
    <tr mat-row *matRowDef="let element; columns: columnsToDisplay;"
      class="example-element-row"
      [class.example-expanded-row]="expandedElement === element"
      (click)="expandedElement = expandedElement === element ? null : element">
    </tr>
    <tr mat-row *matRowDef="let row; columns: ['expandedDetail']"
      class="example-detail-row"></tr>
  </table>
</div>

We keep app.module.ts the same as before.

In app.component.ts , we add the detailExpand animation to show an animation when we toggle the table row.

In app.component.html , we added a new ng-container with the matColumnDef set to expandedDetail .

It spans the whole table’s width.

The detailExpand animation is used in this div.

The columns property in the bottom is set to [‘expandedDetail’] to add the detail column.

Conclusion

We can add basic tables and tables with expanded rows with Angular Material.

Categories
Angular Material

Angular Material — Stepper

Angular Material is a popular UI framework based on Material Design for Angular.

In this article, we’ll look at how to use Angular Material into our Angular project.

Stepper

We can add steps display with the mat-horizontal-stepper component.

For example, we can write:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatStepperModule } from '@angular/material/stepper';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatStepperModule,
    MatFormFieldModule,
    FormsModule,
    ReactiveFormsModule,
    MatInputModule,
    MatButtonModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  firstFormGroup: FormGroup;
  secondFormGroup: FormGroup;
  isEditable = false;

  constructor(private _formBuilder: FormBuilder) { }

  ngOnInit() {
    this.firstFormGroup = this._formBuilder.group({
      firstCtrl: ['', Validators.required]
    });
    this.secondFormGroup = this._formBuilder.group({
      secondCtrl: ['', Validators.required]
    });
  }
}

app.component.html

<div>
  <mat-horizontal-stepper linear #stepper>
    <mat-step [stepControl]="firstFormGroup" [editable]="true">
      <form [formGroup]="firstFormGroup">
        <ng-template matStepLabel>Fill out your name</ng-template>
        <mat-form-field>
          <mat-label>Name</mat-label>
          <input matInput formControlName="firstCtrl"
            placeholder="Name" required>
        </mat-form-field>
        <div>
          <button mat-button matStepperNext>Next</button>
        </div>
      </form>
    </mat-step>
    <mat-step [stepControl]="secondFormGroup" [editable]="true">
      <form [formGroup]="secondFormGroup">
        <ng-template matStepLabel>Fill out your address</ng-template>
        <mat-form-field>
          <mat-label>Address</mat-label>
          <input matInput formControlName="secondCtrl"
            placeholder="Address" required>
        </mat-form-field>
        <div>
          <button mat-button matStepperPrevious>Back</button>
          <button mat-button matStepperNext>Next</button>
        </div>
      </form>
    </mat-step>
    <mat-step>
      <ng-template matStepLabel>Done</ng-template>
      <p>You are now done.</p>
      <div>
        <button mat-button matStepperPrevious>Back</button>
        <button mat-button (click)="stepper.reset()">Reset</button>
      </div>
    </mat-step>
  </mat-horizontal-stepper>
</div>

We add the MatStepperModule to let us add the mat-horizontal-stepper and mat-step components.

The MatFormFieldComponent lets us add a form field.

The FormsModule and ReactiveFormsModule let us add the form validation to our app.

MatInputModule lets us add inputs to mat-form-fields with the matInput directive.

MatButtonModule lets us add Material Design style buttons.

In app.component.ts , we add the reactive forms.

Then in app.component.html , we add the mat-horizontal-stepper to add the stepper.

The mat-step components have the steps.

Each step has its own form with its own form field.

The editable attribute makes the step editable.

The matStepperNext directive makes the button go to the next step.

The formControlName attribute sets the form control name to the ones defined in the component class so that we can add form validation.

We need to add the formGroup attribute for this to work.

The stepper.reset method resets the stepper state.

Conclusion

We can add a stepper with the mat-step and mat-horizontal-stepper components.