Table editor
Angular Bootstrap 5 Table editor plugin
Table Editor is a useful tool for displaying and managing data. The component works similarly to the Datatable (docs) with an additional column for action buttons.
Responsive interactive built with Bootstrap 5, Angular and Material Design. Creates editable tables. Delete or edit rows directly or via modal editor.Note: Examples use additional components such as Datatables, Modal, Alerts and Popconfirm. Remember to import them.
Basic example
Company | Address | Employees |
---|---|---|
Smith & Johnson | Park Lane 2, London | 30 |
P.J. Company | Oak Street 7, Aberdeen | 80 |
Food & Wine | Netherhall Gardens 3, Hampstead | 12 |
IT Service | Warwick Road 14, London | 17 |
A. Jonson Gallery | Oaklands Avenue 2, London | 4 |
F.A. Architects | Frognal Way 7, Hampstead | 4 |
<div class="d-flex justify-content-end mb-4">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
id="search-input"
[disabled]="addRow || editElementIndex !== -1"
(keyup)="search($event)"
/>
<label mdbLabel class="form-label" for="search-input">Search</label>
</mdb-form-control>
<button
mdbRipple
class="btn btn-primary btn-sm ms-3"
[disabled]="addRow || editElementIndex !== -1"
(click)="addRow = true"
>
<i class="fa fa-plus"></i>
</button>
</div>
<hr />
<div
class="datatable table-editor mt-4"
[ngClass]="{ 'edited-table': addRow || editElementIndex !== -1 }"
>
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sort="mdbTableSort"
[dataSource]="dataSource"
[sort]="sort"
[pagination]="pagination"
>
<thead class="datatable-header">
<tr>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header.field"
[disableSort]="header.disableSort"
scope="col"
>
{{ header.label | titlecase }}
</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody class="datatable-body">
<tr
*ngIf="addRow"
[ngClass]="{ 'edited-row': addRow }"
scope="row"
cdkTrapFocus
cdkTrapFocusAutoCapture="true"
>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.company"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.address"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="newRow.employees"
/>
</mdb-form-control>
</td>
<td>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="addNewRow()"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="discardNewRow()"
>
<i class="fa fa-ban"></i>
</button>
</td>
</tr>
<tr
*ngFor="let data of table.data; let index = index"
scope="row"
[cdkTrapFocus]="editElementIndex === index"
[cdkTrapFocusAutoCapture]="editElementIndex === index"
[ngClass]="{ 'edited-row': editElementIndex === index }"
>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.company }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.company"
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.address }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.address"
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.employees }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="data.employees"
/>
</mdb-form-control>
</ng-container>
</td>
<td>
<ng-container
*ngIf="editElementIndex === -1 || editElementIndex !== index"
>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark edit-button"
(click)="onEditClick(index)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-edit"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark delete-button"
(click)="onDeleteClick(data)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-trash-alt"></i>
</button>
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="editElementIndex = -1"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="onDiscardEdit(index)"
>
<i class="fa fa-ban"></i>
</button>
</ng-container>
</td>
</tr>
</tbody>
</table>
<mdb-table-pagination
#pagination
[entries]="5"
[disabled]="addRow || editElementIndex !== -1"
></mdb-table-pagination>
</div>
import { Component, ViewChild } from '@angular/core';
import { MdbTableDirective } from 'mdb-angular-ui-kit/table';
export interface Person {
company: string;
address: string;
employees: number | null;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('table') table!: MdbTableDirective<Person>;
editElementIndex = -1;
addRow = false;
newRow: Person = {
company: '',
address: '',
employees: null,
};
editRow: Person = {
company: '',
address: '',
employees: null,
};
headers = [
{ label: 'Company', field: 'company', disableSort: false },
{ label: 'Address', field: 'address', disableSort: true },
{ label: 'Employees', field: 'employees', disableSort: true },
];
dataSource: Person[] = [
{
company: 'Smith & Johnson',
address: 'Park Lane 2, London',
employees: 30,
},
{
company: 'P.J. Company',
address: 'Oak Street 7, Aberdeen',
employees: 80,
},
{
company: 'Food & Wine',
address: 'Netherhall Gardens 3, Hampstead',
employees: 12,
},
{
company: 'IT Service',
address: 'Warwick Road 14, London',
employees: 17,
},
{
company: 'A. Jonson Gallery',
address: 'Oaklands Avenue 2, London',
employees: 4,
},
{
company: 'F.A. Architects',
address: 'Frognal Way 7, Hampsteadn',
employees: 4,
},
];
constructor() {}
search(event: Event): void {
const searchTerm = (event.target as HTMLInputElement).value;
this.table.search(searchTerm);
}
addNewRow(): void {
this.dataSource = [...this.dataSource, { ...this.newRow }];
this.newRow.company = '';
this.newRow.address = '';
this.newRow.employees = null;
this.addRow = false;
}
discardNewRow(): void {
this.newRow.company = '';
this.newRow.address = '';
this.newRow.employees = null;
this.addRow = false;
}
onEditClick(index: number): void {
this.editElementIndex = index;
this.editRow = { ...this.table.data[index] };
}
onDiscardEdit(index: number): void {
this.editElementIndex = -1;
this.table.data[index] = { ...this.editRow };
}
onDeleteClick(data: Person): void {
const index = this.dataSource.indexOf(data);
this.dataSource.splice(index, 1);
this.dataSource = [...this.dataSource];
}
}
Modal
Note: This example use Modal. Remember to import them.
<div class="d-flex justify-content-end mb-4">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
id="search-input"
(keyup)="search($event)"
/>
<label mdbLabel class="form-label" for="search-input">Search</label>
</mdb-form-control>
<button
mdbRipple
class="btn btn-primary btn-sm ms-3"
(click)="openModal('add')"
>
<i class="fa fa-plus"></i>
</button>
</div>
<hr />
<div class="datatable table-editor mt-4">
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sort="mdbTableSort"
[dataSource]="dataSource"
[sort]="sort"
[pagination]="pagination"
>
<thead class="datatable-header">
<tr>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header.field"
[disableSort]="header.disableSort"
scope="col"
>
{{ header.label | titlecase }}
</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody class="datatable-body">
<tr *ngFor="let data of table.data; let index = index" scope="row">
<td style="min-width: 250px; max-width: 250px">
{{ data.company }}
</td>
<td style="min-width: 250px; max-width: 250px">
{{ data.office }}
</td>
<td style="min-width: 250px; max-width: 250px">
{{ data.employees }}
</td>
<td style="min-width: 100px; max-width: 100px">
{{ data.international }}
</td>
<td>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark edit-button"
(click)="openModal('edit', data)"
>
<i class="far fa-edit"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark delete-button"
(click)="onDeleteClick(data)"
>
<i class="far fa-trash-alt"></i>
</button>
</td>
</tr>
</tbody>
</table>
<mdb-table-pagination #pagination [entries]="5"></mdb-table-pagination>
</div>
import { Component, ViewChild } from '@angular/core';
import { MdbModalRef, MdbModalService } from 'mdb-angular-ui-kit/modal';
import { MdbTableDirective } from 'mdb-angular-ui-kit/table';
import { ModalComponent } from './modal.component';
export interface Person {
company: string;
office: string;
employees: number | null;
international: boolean;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('table') table!: MdbTableDirective<Person>;
modalRef: MdbModalRef<ModalComponent> | null = null;
headers = [
{ label: 'Company', field: 'company', disableSort: false },
{ label: 'Office', field: 'office', disableSort: true },
{ label: 'Employees', field: 'employees', disableSort: false },
{ label: 'International', field: 'international', disableSort: false },
];
dataSource: Person[] = [
{
company: 'Smith & Johnson',
office: 'London',
employees: 30,
international: true,
},
{
company: 'P.J. Company',
office: 'London',
employees: 80,
international: false,
},
{
company: 'Food & Wine',
office: 'London',
employees: 12,
international: false,
},
{
company: 'IT Service',
office: 'London',
employees: 17,
international: false,
},
{
company: 'A. Jonson Gallery',
office: 'London',
employees: 4,
international: false,
},
{
company: 'F.A. Architects',
office: 'London',
employees: 4,
international: false,
},
];
constructor(private modalService: MdbModalService) {}
search(event: Event): void {
const searchTerm = (event.target as HTMLInputElement).value;
this.table.search(searchTerm);
}
openModal(mode: 'add' | 'edit', data?: Person): void {
this.modalRef = this.modalService.open(ModalComponent, {
data: {
modalTitle: mode === 'edit' ? 'Edit item' : 'New item',
company: data ? data.company : '',
office: data ? data.office : 'Warsaw',
employees: data ? data.employees : 1,
international: data ? data.international : false,
},
ignoreBackdropClick: true,
});
this.modalRef.onClose.subscribe((modalData: Person) => {
if (!modalData) {
return;
}
if (mode === 'add') {
this.dataSource = [...this.dataSource, { ...modalData }];
} else if (mode === 'edit' && data) {
const index = this.dataSource.indexOf(data);
this.dataSource[index] = modalData;
this.dataSource = [...this.dataSource];
}
});
}
onDeleteClick(data: Person): void {
const index = this.dataSource.indexOf(data);
this.dataSource.splice(index, 1);
this.dataSource = [...this.dataSource];
}
}
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{{ modalTitle }}</h5>
</div>
<div class="modal-body">
<div class="my-4 table-editor_input-wrapper">
<mdb-form-control>
<input
mdbInput
type="text"
id="company-input"
class="form-control"
[(ngModel)]="company"
/>
<label mdbLabel class="form-label" for="company-input">Company</label>
</mdb-form-control>
</div>
<div class="my-4 table-editor_input-wrapper">
<mdb-form-control>
<mdb-select [(ngModel)]="office">
<mdb-option *ngFor="let option of options" [value]="option.value">{{
option.label
}}</mdb-option>
</mdb-select>
<label mdbLabel class="form-label">Office</label>
</mdb-form-control>
</div>
<div class="my-4 table-editor_input-wrapper">
<mdb-form-control>
<input
mdbInput
type="number"
id="employees-input"
class="form-control"
[(ngModel)]="employees"
/>
<label mdbLabel class="form-label" for="employees-input">Employees</label>
</mdb-form-control>
</div>
<div class="my-4 table-editor_input-wrapper">
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
value=""
id="international-checkbox"
[(ngModel)]="international"
/>
<label class="form-check-label" for="flexCheckDefault">
International
</label>
</div>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="shadow-0 btn btn-md btn-outline-primary"
(click)="modalRef.close()"
>
Cancel
</button>
<button
type="button"
class="shadow-0 btn btn-md btn-primary"
(click)="saveData()"
>
Save
</button>
</div>
import { Component } from '@angular/core';
import { MdbModalRef } from 'mdb-angular-ui-kit/modal';
@Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
})
export class ModalComponent {
modalTitle: string | null = null;
company: string | null = null;
office: string | null = null;
employees: string | null = null;
international: string | null = null;
options = [
{ value: 'London', label: 'London' },
{ value: 'Warsaw', label: 'Warsaw' },
{ value: 'New York', label: 'New York' },
];
constructor(public modalRef: MdbModalRef<ModalComponent>) {}
saveData(): void {
const closeMessage = {
company: this.company,
office: this.office,
employees: this.employees,
international: this.international,
};
this.modalRef.close(closeMessage);
}
}
Inputs example
<div class="d-flex justify-content-end mb-4">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
id="search-input"
[disabled]="addRow || editElementIndex !== -1"
(keyup)="search($event)"
/>
<label mdbLabel class="form-label" for="search-input">Search</label>
</mdb-form-control>
<button
mdbRipple
class="btn btn-primary btn-sm ms-3"
[disabled]="addRow || editElementIndex !== -1"
(click)="addRow = true"
>
<i class="fa fa-plus"></i>
</button>
</div>
<hr />
<div
class="datatable table-editor mt-4"
[ngClass]="{
'edited-table': addRow || editElementIndex !== -1
}"
>
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sort="mdbTableSort"
[dataSource]="dataSource"
[sort]="sort"
[pagination]="pagination"
>
<thead class="datatable-header">
<tr>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header.field"
[disableSort]="header.disableSort"
scope="col"
>
{{ header.label | titlecase }}
</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody class="datatable-body">
<tr
*ngIf="addRow"
[ngClass]="{ 'edited-row': addRow }"
scope="row"
cdkTrapFocus
cdkTrapFocusAutoCapture="true"
>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.company"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<mdb-select [(ngModel)]="newRow.office">
<mdb-option
*ngFor="let option of options"
[value]="option.value"
>{{ option.label }}</mdb-option
>
</mdb-select>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="newRow.employees"
/>
</mdb-form-control>
</td>
<td>
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
[(ngModel)]="newRow.international"
/>
</div>
</td>
<td>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="addNewRow()"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="discardNewRow()"
>
<i class="fa fa-ban"></i>
</button>
</td>
</tr>
<tr
*ngFor="let data of table.data; let index = index"
scope="row"
[cdkTrapFocus]="editElementIndex === index"
[cdkTrapFocusAutoCapture]="editElementIndex === index"
[ngClass]="{ 'edited-row': editElementIndex === index }"
>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.company }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.company"
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.office }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<mdb-select [(ngModel)]="data.office">
<mdb-option
*ngFor="let option of options"
[value]="option.value"
>{{ option.label }}</mdb-option
>
</mdb-select>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.employees }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="data.employees"
/>
</mdb-form-control>
</ng-container>
</td>
<td>
<ng-container *ngIf="editElementIndex !== index">
{{ data.international }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
[(ngModel)]="data.international"
/>
</div>
</ng-container>
</td>
<td>
<ng-container
*ngIf="editElementIndex === -1 || editElementIndex !== index"
>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark edit-button"
(click)="onEditClick(index)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-edit"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark delete-button"
(click)="onDeleteClick(data)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-trash-alt"></i>
</button>
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="editElementIndex = -1"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="onDiscardEdit(index)"
>
<i class="fa fa-ban"></i>
</button>
</ng-container>
</td>
</tr>
</tbody>
</table>
<mdb-table-pagination
#pagination
[entries]="5"
[disabled]="addRow || editElementIndex !== -1"
></mdb-table-pagination>
</div>
import { Component, ViewChild } from '@angular/core';
import { MdbTableDirective } from 'mdb-angular-ui-kit/table';
export interface Person {
company: string;
office: string;
employees: number | null;
international: boolean;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('table') table!: MdbTableDirective<Person>;
editElementIndex = -1;
addRow = false;
newRow: Person = {
company: '',
office: 'Warsaw',
employees: 1,
international: false,
};
editRow: Person = {
company: '',
office: '',
employees: null,
international: false,
};
options = [
{ value: 'London', label: 'London' },
{ value: 'Warsaw', label: 'Warsaw' },
{ value: 'New York', label: 'New York' },
];
headers = [
{ label: 'Company', field: 'company', disableSort: false },
{ label: 'Office', field: 'office', disableSort: true },
{ label: 'Employees', field: 'employees', disableSort: false },
{ label: 'International', field: 'international', disableSort: false },
];
dataSource: Person[] = [
{
company: 'Smith & Johnson',
office: 'London',
employees: 30,
international: true,
},
{
company: 'P.J. Company',
office: 'London',
employees: 80,
international: false,
},
{
company: 'Food & Wine',
office: 'London',
employees: 12,
international: false,
},
{
company: 'IT Service',
office: 'London',
employees: 17,
international: false,
},
{
company: 'A. Jonson Gallery',
office: 'London',
employees: 4,
international: false,
},
{
company: 'F.A. Architects',
office: 'London',
employees: 4,
international: false,
},
];
constructor() {}
search(event: Event): void {
const searchTerm = (event.target as HTMLInputElement).value;
this.table.search(searchTerm);
}
addNewRow(): void {
this.dataSource = [...this.dataSource, { ...this.newRow }];
this.newRow.company = '';
this.newRow.office = 'Warsaw';
this.newRow.employees = 1;
this.newRow.international = false;
this.addRow = false;
}
discardNewRow(): void {
this.newRow.company = '';
this.newRow.office = 'Warsaw';
this.newRow.employees = 1;
this.newRow.international = false;
this.addRow = false;
}
onEditClick(index: number): void {
this.editElementIndex = index;
this.editRow = { ...this.table.data[index] };
}
onDiscardEdit(index: number): void {
this.editElementIndex = -1;
this.table.data[index] = { ...this.editRow };
}
onDeleteClick(data: Person): void {
const index = this.dataSource.indexOf(data);
this.dataSource.splice(index, 1);
this.dataSource = [...this.dataSource];
}
}
Disable edit
<div class="d-flex justify-content-end mb-4">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
id="search-input"
[disabled]="addRow || editElementIndex !== -1"
(keyup)="search($event)"
/>
<label mdbLabel class="form-label" for="search-input">Search</label>
</mdb-form-control>
<button
mdbRipple
class="btn btn-primary btn-sm ms-3"
[disabled]="addRow || editElementIndex !== -1"
(click)="addRow = true"
>
<i class="fa fa-plus"></i>
</button>
</div>
<hr />
<div
class="datatable table-editor mt-4"
[ngClass]="{
'edited-table': addRow || editElementIndex !== -1
}"
>
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sort="mdbTableSort"
[dataSource]="dataSource"
[sort]="sort"
[pagination]="pagination"
>
<thead class="datatable-header">
<tr>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header.field"
[disableSort]="header.disableSort"
scope="col"
>
{{ header.label | titlecase }}
</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody class="datatable-body">
<tr
*ngIf="addRow"
scope="row"
cdkTrapFocus
cdkTrapFocusAutoCapture="true"
[ngClass]="{ 'edited-row': addRow }"
>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.company"
disabled
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<mdb-select [(ngModel)]="newRow.office" disabled>
<mdb-option
*ngFor="let option of options"
[value]="option.value"
>{{ option.label }}</mdb-option
>
</mdb-select>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="newRow.employees"
disabled
/>
</mdb-form-control>
</td>
<td>
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
[(ngModel)]="newRow.international"
disabled
/>
</div>
</td>
<td>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="addNewRow()"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="discardNewRow()"
>
<i class="fa fa-ban"></i>
</button>
</td>
</tr>
<tr
*ngFor="let data of table.data; let index = index"
scope="row"
[cdkTrapFocus]="editElementIndex === index"
[cdkTrapFocusAutoCapture]="editElementIndex === index"
[ngClass]="{
'edited-row': editElementIndex === index
}"
>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.company }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.company"
disabled
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.office }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<mdb-select [(ngModel)]="data.office" [disabled]="true">
<mdb-option
*ngFor="let option of options"
[value]="option.value"
>{{ option.label }}</mdb-option
>
</mdb-select>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.employees }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="data.employees"
disabled
/>
</mdb-form-control>
</ng-container>
</td>
<td>
<ng-container *ngIf="editElementIndex !== index">
{{ data.international }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
[(ngModel)]="data.international"
disabled
/>
</div>
</ng-container>
</td>
<td>
<ng-container
*ngIf="editElementIndex === -1 || editElementIndex !== index"
>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark edit-button"
(click)="editElementIndex = index"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-edit"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark delete-button"
(click)="onDeleteClick(data)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-trash-alt"></i>
</button>
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="editElementIndex = -1"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="editElementIndex = -1"
>
<i class="fa fa-ban"></i>
</button>
</ng-container>
</td>
</tr>
</tbody>
</table>
<mdb-table-pagination
#pagination
[entries]="5"
[disabled]="addRow || editElementIndex !== -1"
></mdb-table-pagination>
</div>
import { Component, ViewChild } from '@angular/core';
import { MdbTableDirective } from 'mdb-angular-ui-kit/table';
export interface Person {
company: string;
office: string;
employees: number | null;
international: boolean;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('table') table!: MdbTableDirective<Person>;
editElementIndex = -1;
addRow = false;
newRow: Person = {
company: '',
office: 'Warsaw',
employees: 1,
international: false,
};
options = [
{ value: 'London', label: 'London' },
{ value: 'Warsaw', label: 'Warsaw' },
{ value: 'New York', label: 'New York' },
];
headers = [
{ label: 'Company', field: 'company', disableSort: false },
{ label: 'Office', field: 'office', disableSort: true },
{ label: 'Employees', field: 'employees', disableSort: false },
{ label: 'International', field: 'international', disableSort: false },
];
dataSource: Person[] = [
{
company: 'Smith & Johnson',
office: 'London',
employees: 30,
international: true,
},
{
company: 'P.J. Company',
office: 'London',
employees: 80,
international: false,
},
{
company: 'Food & Wine',
office: 'London',
employees: 12,
international: false,
},
{
company: 'IT Service',
office: 'London',
employees: 17,
international: false,
},
{
company: 'A. Jonson Gallery',
office: 'London',
employees: 4,
international: false,
},
{
company: 'F.A. Architects',
office: 'London',
employees: 4,
international: false,
},
];
constructor() {}
search(event: Event): void {
const searchTerm = (event.target as HTMLInputElement).value;
this.table.search(searchTerm);
}
addNewRow(): void {
this.dataSource = [...this.dataSource, { ...this.newRow }];
this.newRow.company = '';
this.newRow.office = 'Warsaw';
this.newRow.employees = 1;
this.newRow.international = false;
this.addRow = false;
}
discardNewRow(): void {
this.newRow.company = '';
this.newRow.office = 'Warsaw';
this.newRow.employees = 1;
this.newRow.international = false;
this.addRow = false;
}
onDeleteClick(data: Person): void {
const index = this.dataSource.indexOf(data);
this.dataSource.splice(index, 1);
this.dataSource = [...this.dataSource];
}
}
Confirm delete
Note: This example use Popconfirm. Remember to import them.
<div class="d-flex justify-content-end mb-4">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
id="search-input"
[disabled]="addRow || editElementIndex !== -1"
(keyup)="search($event)"
/>
<label mdbLabel class="form-label" for="search-input">Search</label>
</mdb-form-control>
<button
mdbRipple
class="btn btn-primary btn-sm ms-3"
[disabled]="addRow || editElementIndex !== -1"
(click)="addRow = true"
>
<i class="fa fa-plus"></i>
</button>
</div>
<hr />
<div
class="datatable table-editor mt-4"
[ngClass]="{
'edited-table': addRow || editElementIndex !== -1
}"
>
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sort="mdbTableSort"
[dataSource]="dataSource"
[sort]="sort"
[pagination]="pagination"
>
<thead class="datatable-header">
<tr>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header.field"
[disableSort]="header.disableSort"
scope="col"
>
{{ header.label | titlecase }}
</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody class="datatable-body">
<tr
*ngIf="addRow"
[ngClass]="{ 'edited-row': addRow }"
scope="row"
cdkTrapFocus
cdkTrapFocusAutoCapture="true"
>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.company"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<mdb-select [(ngModel)]="newRow.office">
<mdb-option
*ngFor="let option of options"
[value]="option.value"
>{{ option.label }}</mdb-option
>
</mdb-select>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="newRow.employees"
/>
</mdb-form-control>
</td>
<td>
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
[(ngModel)]="newRow.international"
/>
</div>
</td>
<td>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="addNewRow()"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="discardNewRow()"
>
<i class="fa fa-ban"></i>
</button>
</td>
</tr>
<tr
*ngFor="let data of table.data; let index = index"
scope="row"
[cdkTrapFocus]="editElementIndex === index"
[cdkTrapFocusAutoCapture]="editElementIndex === index"
[ngClass]="{ 'edited-row': editElementIndex === index }"
>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.company }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.company"
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.office }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<mdb-select [(ngModel)]="data.office">
<mdb-option
*ngFor="let option of options"
[value]="option.value"
>{{ option.label }}</mdb-option
>
</mdb-select>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.employees }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="data.employees"
/>
</mdb-form-control>
</ng-container>
</td>
<td>
<ng-container *ngIf="editElementIndex !== index">
{{ data.international }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
[(ngModel)]="data.international"
/>
</div>
</ng-container>
</td>
<td>
<ng-container
*ngIf="editElementIndex === -1 || editElementIndex !== index"
>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark edit-button"
(click)="onEditClick(index)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-edit"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark delete-button"
#target
(click)="openPopconfirm(target, data)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-trash-alt"></i>
</button>
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="editElementIndex = -1"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="onDiscardEdit(index)"
>
<i class="fa fa-ban"></i>
</button>
</ng-container>
</td>
</tr>
</tbody>
</table>
<mdb-table-pagination
#pagination
[entries]="5"
[disabled]="addRow || editElementIndex !== -1"
></mdb-table-pagination>
</div>
import { Component, ViewChild } from '@angular/core';
import {
MdbPopconfirmRef,
MdbPopconfirmService,
} from 'mdb-angular-ui-kit/popconfirm';
import { MdbTableDirective } from 'mdb-angular-ui-kit/table';
import { PopconfirmComponent } from './popconfirm.component';
export interface Person {
company: string;
office: string;
employees: number | null;
international: boolean;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('table') table!: MdbTableDirective<Person>;
popconfirmRef: MdbPopconfirmRef<PopconfirmComponent> | null = null;
editElementIndex = -1;
addRow = false;
newRow: Person = {
company: '',
office: 'Warsaw',
employees: 1,
international: false,
};
editRow: Person = {
company: '',
office: '',
employees: null,
international: false,
};
headers = [
{ label: 'Company', field: 'company', disableSort: false },
{ label: 'Office', field: 'office', disableSort: true },
{ label: 'Employees', field: 'employees', disableSort: false },
{ label: 'International', field: 'international', disableSort: false },
];
options = [
{ value: 'London', label: 'London' },
{ value: 'Warsaw', label: 'Warsaw' },
{ value: 'New York', label: 'New York' },
];
dataSource: Person[] = [
{
company: 'Smith & Johnson',
office: 'London',
employees: 30,
international: true,
},
{
company: 'P.J. Company',
office: 'London',
employees: 80,
international: false,
},
{
company: 'Food & Wine',
office: 'London',
employees: 12,
international: false,
},
{
company: 'IT Service',
office: 'London',
employees: 17,
international: false,
},
{
company: 'A. Jonson Gallery',
office: 'London',
employees: 4,
international: false,
},
{
company: 'F.A. Architects',
office: 'London',
employees: 4,
international: false,
},
];
constructor(private popconfirmService: MdbPopconfirmService) {}
search(event: Event): void {
const searchTerm = (event.target as HTMLInputElement).value;
this.table.search(searchTerm);
}
addNewRow() {
this.dataSource = [...this.dataSource, { ...this.newRow }];
this.newRow.company = '';
this.newRow.office = 'Warsaw';
this.newRow.employees = 1;
this.newRow.international = false;
this.addRow = false;
}
discardNewRow(): void {
this.newRow.company = '';
this.newRow.office = 'Warsaw';
this.newRow.employees = 1;
this.newRow.international = false;
this.addRow = false;
}
onEditClick(index: number): void {
this.editElementIndex = index;
this.editRow = { ...this.table.data[index] };
}
onDiscardEdit(index: number): void {
this.editElementIndex = -1;
this.table.data[index] = { ...this.editRow };
}
onDeleteClick(data: Person): void {
const index = this.dataSource.indexOf(data);
this.dataSource.splice(index, 1);
this.dataSource = [...this.dataSource];
}
openPopconfirm(target: HTMLElement, data: Person): void {
this.popconfirmRef = this.popconfirmService.open(
PopconfirmComponent,
target,
{ data: { data: data } }
);
this.popconfirmRef.onClose.subscribe(() => {
this.editElementIndex = -1;
});
this.popconfirmRef.onConfirm.subscribe((data) => {
this.onDeleteClick(data);
});
}
}
<div class="popconfirm-popover shadow-4">
<div class="popconfirm">
<p class="popconfirm-message">
<span class="popconfirm-message-text"
>Are you sure you want to delete this entry?</span
>
</p>
<div class="popconfirm-buttons-container">
<button
(click)="popconfirmRef.close()"
type="button"
aria-label="Cancel"
class="btn btn-flat btn-sm"
>
Cancel
</button>
<button
(click)="popconfirmRef.confirm(data)"
type="button"
aria-label="Confirm"
class="btn btn-primary btn-sm"
>
Delete
</button>
</div>
</div>
</div>
import { Component, OnInit } from '@angular/core';
import { MdbPopconfirmRef } from 'mdb-angular-ui-kit/popconfirm';
@Component({
selector: 'app-popconfirm',
templateUrl: './popconfirm.component.html',
})
export class PopconfirmComponent implements OnInit {
data: any = null;
constructor(public popconfirmRef: MdbPopconfirmRef<PopconfirmComponent>) {}
ngOnInit(): void {}
}
Advanced Search
<div class="d-flex justify-content-between mb-4">
<div class="d-flex">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
id="search-input"
[disabled]="addRow || editElementIndex !== -1"
#searchInput
/>
<label mdbLabel class="form-label" for="search-input">Search</label>
</mdb-form-control>
<div class="px-3 mt-1">in:</div>
<mdb-form-control>
<mdb-select
[(ngModel)]="selectValue"
[disabled]="addRow || editElementIndex !== -1"
>
<mdb-option [value]="'all'">All columns</mdb-option>
<mdb-option [value]="'company'">Company</mdb-option>
<mdb-option [value]="'office'">Office</mdb-option>
</mdb-select>
</mdb-form-control>
<button
class="btn btn-outline-primary btn-sm mx-2"
(click)="search(searchInput.value)"
[disabled]="editElementIndex !== -1"
>
<i class="fa fa-search"></i>
</button>
</div>
<button
mdbRipple
class="btn btn-primary btn-sm ms-3"
[disabled]="addRow || editElementIndex !== -1"
(click)="addRow = true"
>
<i class="fa fa-plus"></i>
</button>
</div>
<hr />
<div
class="datatable table-editor mt-4"
[ngClass]="{
'edited-table': addRow || editElementIndex !== -1
}"
>
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sort="mdbTableSort"
[dataSource]="dataSource"
[sort]="sort"
[pagination]="pagination"
[filterFn]="filterFn"
>
<thead class="datatable-header">
<tr>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header.field"
[disableSort]="header.disableSort"
scope="col"
>
{{ header.label | titlecase }}
</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody class="datatable-body">
<tr
*ngIf="addRow"
[ngClass]="{ 'edited-row': addRow }"
scope="row"
cdkTrapFocus
cdkTrapFocusAutoCapture="true"
>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.company"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<mdb-select [(ngModel)]="newRow.office">
<mdb-option
*ngFor="let option of options"
[value]="option.value"
>{{ option.label }}</mdb-option
>
</mdb-select>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="newRow.employees"
/>
</mdb-form-control>
</td>
<td>
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
[(ngModel)]="newRow.international"
/>
</div>
</td>
<td>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="addNewRow()"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="discardNewRow()"
>
<i class="fa fa-ban"></i>
</button>
</td>
</tr>
<tr scope="row" *ngIf="!table.data?.length">
<td style="min-width: 250px; max-width: 250px">
No matching results found
</td>
</tr>
<tr
*ngFor="let data of table.data; let index = index"
scope="row"
[cdkTrapFocus]="editElementIndex === index"
[cdkTrapFocusAutoCapture]="editElementIndex === index"
[ngClass]="{
'edited-row': editElementIndex === index
}"
>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.company }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.company"
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.office }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<mdb-select [(ngModel)]="data.office">
<mdb-option
*ngFor="let option of options"
[value]="option.value"
>{{ option.label }}</mdb-option
>
</mdb-select>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.employees }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="data.employees"
/>
</mdb-form-control>
</ng-container>
</td>
<td>
<ng-container *ngIf="editElementIndex !== index">
{{ data.international }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
[(ngModel)]="data.international"
/>
</div>
</ng-container>
</td>
<td>
<ng-container
*ngIf="editElementIndex === -1 || editElementIndex !== index"
>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark edit-button"
(click)="onEditClick(index)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-edit"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark delete-button"
(click)="onDeleteClick(data)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-trash-alt"></i>
</button>
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="editElementIndex = -1"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="onDiscardEdit(index)"
>
<i class="fa fa-ban"></i>
</button>
</ng-container>
</td>
</tr>
</tbody>
</table>
<mdb-table-pagination
#pagination
[entries]="5"
[disabled]="addRow || editElementIndex !== -1"
></mdb-table-pagination>
</div>
import { Component, ViewChild } from '@angular/core';
import { MdbTableDirective } from 'mdb-angular-ui-kit/table';
export interface Person {
company: string;
office: string;
employees: number | null;
international: boolean;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('table') table!: MdbTableDirective<Person>;
editElementIndex = -1;
addRow = false;
selectValue = 'all';
newRow: Person = {
company: '',
office: 'Warsaw',
employees: 1,
international: false,
};
editRow: Person = {
company: '',
office: '',
employees: null,
international: false,
};
options = [
{ value: 'London', label: 'London' },
{ value: 'Warsaw', label: 'Warsaw' },
{ value: 'New York', label: 'New York' },
];
headers = [
{ label: 'Company', field: 'company', disableSort: false },
{ label: 'Office', field: 'office', disableSort: true },
{ label: 'Employees', field: 'employees', disableSort: false },
{ label: 'International', field: 'international', disableSort: false },
];
dataSource: Person[] = [
{
company: 'Smith & Johnson',
office: 'London',
employees: 30,
international: true,
},
{
company: 'P.J. Company',
office: 'London',
employees: 80,
international: false,
},
{
company: 'Food & Wine',
office: 'London',
employees: 12,
international: false,
},
{
company: 'IT Service',
office: 'London',
employees: 17,
international: false,
},
{
company: 'A. Jonson Gallery',
office: 'London',
employees: 4,
international: false,
},
{
company: 'F.A. Architects',
office: 'London',
employees: 4,
international: false,
},
];
constructor() {}
search(value: string): void {
let searchTerm = value;
if (this.selectValue !== 'all') {
searchTerm = `${value} in: ${this.selectValue}`;
}
this.table.search(searchTerm);
}
filterFn(data: any, searchTerm: string): boolean {
// tslint:disable-next-line: prefer-const
let [phrase, columns] = searchTerm.split(' in:').map((str) => str.trim());
return Object.keys(data).some((key: any) => {
if (columns?.length) {
let result;
columns.split(',').forEach((column) => {
if (
column.toLowerCase().trim() === key.toLowerCase() &&
data[key].toLowerCase().includes(phrase.toLowerCase())
) {
result = true;
}
});
return result;
}
if (data[key] && !columns?.length) {
return JSON.stringify(data)
.toLowerCase()
.includes(phrase.toLowerCase());
}
return;
});
}
addNewRow(): void {
this.dataSource = [...this.dataSource, { ...this.newRow }];
this.newRow.company = '';
this.newRow.office = 'Warsaw';
this.newRow.employees = 1;
this.newRow.international = false;
this.addRow = false;
}
discardNewRow(): void {
this.newRow.company = '';
this.newRow.office = 'Warsaw';
this.newRow.employees = 1;
this.newRow.international = false;
this.addRow = false;
}
onEditClick(index: number): void {
this.editElementIndex = index;
this.editRow = { ...this.table.data[index] };
}
onDiscardEdit(index: number): void {
this.editElementIndex = -1;
this.table.data[index] = { ...this.editRow };
}
onDeleteClick(data: Person): void {
const index = this.dataSource.indexOf(data);
this.dataSource.splice(index, 1);
this.dataSource = [...this.dataSource];
}
}
Async data
<div class="d-flex justify-content-between mb-4">
<button class="btn btn-primary btn-sm" (click)="loadData()">Load data</button>
<div class="d-flex">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
id="search-input"
[disabled]="addRow || editElementIndex !== -1 || loading"
(keyup)="search($event)"
/>
<label mdbLabel class="form-label" for="search-input">Search</label>
</mdb-form-control>
<button
mdbRipple
class="btn btn-primary btn-sm ms-3"
[disabled]="addRow || editElementIndex !== -1 || loading"
(click)="addRow = true"
>
<i class="fa fa-plus"></i>
</button>
</div>
</div>
<hr />
<div
class="datatable table-editor mt-4"
[ngClass]="{
'edited-table': addRow || editElementIndex !== -1
}"
>
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sort="mdbTableSort"
[dataSource]="dataSource"
[pagination]="pagination"
[sort]="sort"
>
<thead class="datatable-header">
<tr>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header.field"
[disableSort]="header.disableSort"
scope="col"
>
{{ header.label | titlecase }}
</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody class="datatable-body" *ngIf="!loading">
<tr
*ngIf="addRow"
[ngClass]="{ 'edited-row': addRow }"
scope="row"
cdkTrapFocus
cdkTrapFocusAutoCapture="true"
>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.company"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.email"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.name"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.phone"
/>
</mdb-form-control>
</td>
<td>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="addNewRow()"
>
<i class="fa fa-check"></i>
</button>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="discardNewRow()"
>
<i class="fa fa-ban"></i>
</button>
</td>
</tr>
<tr
*ngFor="let data of table.data; let index = index"
scope="row"
[cdkTrapFocus]="editElementIndex === index"
[cdkTrapFocusAutoCapture]="editElementIndex === index"
[ngClass]="{ 'edited-row': editElementIndex === index }"
>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.company }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.company"
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.email }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.email"
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.name }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.name"
/>
</mdb-form-control>
</ng-container>
</td>
<td>
<ng-container *ngIf="editElementIndex !== index">
{{ data.phone }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.phone"
/>
</mdb-form-control>
</ng-container>
</td>
<td>
<ng-container
*ngIf="editElementIndex === -1 || editElementIndex !== index"
>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark edit-button"
(click)="onEditClick(index)"
[disabled]="editElementIndex !== -1 && editElementIndex !== index"
>
<i class="far fa-edit"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark delete-button"
(click)="onDeleteClick(data)"
[disabled]="editElementIndex !== -1 && editElementIndex !== index"
>
<i class="far fa-trash-alt"></i>
</button>
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="editElementIndex = -1"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="onDiscardEdit(index)"
>
<i class="fa fa-ban"></i>
</button>
</ng-container>
</td>
</tr>
</tbody>
</table>
<ng-container *ngIf="loading">
<div class="datatable-loader bg-light">
<span class="datatable-loader-inner">
<span class="datatable-progress bg-primary"></span>
</span>
</div>
<p class="text-center text-muted my-4">Loading results...</p>
</ng-container>
<mdb-table-pagination
#pagination
[entries]="10"
[disabled]="addRow || editElementIndex !== -1 || loading"
></mdb-table-pagination>
</div>
import { HttpClient } from '@angular/common/http';
import { Component, ViewChild } from '@angular/core';
import { MdbTableDirective } from 'mdb-angular-ui-kit/table';
import { tap, take } from 'rxjs/operators';
interface Person {
company: string;
email: string;
name: string;
phone: string;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('table') table!: MdbTableDirective<Person>;
dataUrl = 'https://jsonplaceholder.typicode.com/users';
loading = true;
editElementIndex = -1;
addRow = false;
newRow: Person = {
company: '',
email: '',
name: '',
phone: '',
};
editRow: Person = {
company: '',
email: '',
name: '',
phone: '',
};
headers = [
{ label: 'Company', field: 'company', disableSort: false },
{ label: 'Email', field: 'email', disableSort: false },
{ label: 'Name', field: 'name', disableSort: false },
{ label: 'Phone', field: 'phone', disableSort: false },
];
dataSource: Person[] = [];
constructor(private _http: HttpClient) {}
loadData() {
this.getData()
.pipe(take(1))
.subscribe((data: any[]) => {
const mappedData = data.map((entry) => {
return { ...entry, company: entry.company.name };
});
this.dataSource = mappedData;
});
}
getData() {
return this._http
.get<any>(this.dataUrl)
.pipe(tap(() => (this.loading = false)));
}
search(event: Event): void {
const searchTerm = (event.target as HTMLInputElement).value;
this.table.search(searchTerm);
}
addNewRow(): void {
this.dataSource = [...this.dataSource, { ...this.newRow }];
this.newRow.company = '';
this.newRow.email = '';
this.newRow.name = '';
this.newRow.phone = '';
this.addRow = false;
}
discardNewRow(): void {
this.newRow.company = '';
this.newRow.email = '';
this.newRow.name = '';
this.newRow.phone = '';
this.addRow = false;
}
onEditClick(index: number): void {
this.editElementIndex = index;
this.editRow.company = this.table.data[index].company;
this.editRow.email = this.table.data[index].email;
this.editRow.name = this.table.data[index].name;
this.editRow.phone = this.table.data[index].phone;
}
onDiscardEdit(index: number): void {
this.editElementIndex = -1;
this.table.data[index].company = this.editRow.company;
this.table.data[index].email = this.editRow.email;
this.table.data[index].name = this.editRow.name;
this.table.data[index].phone = this.editRow.phone;
}
onDeleteClick(data: Person): void {
const index = this.dataSource.indexOf(data);
this.dataSource.splice(index, 1);
this.dataSource = [...this.dataSource];
}
}
Custom rows
M.B.
(5 Avenue 26, New York)
Berkley & Clark
(43th Street 12, New York)
D&D Inc.
(14 Street 67, New York)
Thomas & Co.
(2 Avenue 54, New York)
<div class="row">
<div class="col-md-3 col-sm-6 p-3">
<h4>M.B.</h4>
<p>(5 Avenue 26, New York)</p>
<button
class="btn btn-primary btn-sm"
(click)="loadMB()"
[disabled]="mBLoaded || addRow"
>
{{ mBLoaded ? "Loaded" : "Load into table" }}
</button>
</div>
<div class="col-md-3 col-sm-6 p-3">
<h4>Berkley & Clark</h4>
<p>(43th Street 12, New York)</p>
<button
class="btn btn-primary btn-sm"
(click)="loadBarkleyAndClark()"
[disabled]="barkleyAndClarkLoaded || addRow"
>
{{ barkleyAndClarkLoaded ? "Loaded" : "Load into table" }}
</button>
</div>
<div class="col-md-3 col-sm-6 p-3">
<h4>D&D Inc.</h4>
<p>(14 Street 67, New York)</p>
<button
class="btn btn-primary btn-sm"
(click)="loadDAndDInc()"
[disabled]="dAndDIncLoaded || addRow"
>
{{ dAndDIncLoaded ? "Loaded" : "Load into table" }}
</button>
</div>
<div class="col-md-3 col-sm-6 p-3">
<h4>Thomas & Co.</h4>
<p>(2 Avenue 54, New York)</p>
<button
class="btn btn-primary btn-sm"
(click)="loadThomasAndCo()"
[disabled]="thomasAndCoLoaded || addRow"
>
{{ thomasAndCoLoaded ? "Loaded" : "Load into table" }}
</button>
</div>
</div>
<hr />
<div
class="datatable table-editor mt-4"
[ngClass]="{
'edited-table': addRow || editElementIndex !== -1
}"
>
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sort="mdbTableSort"
[dataSource]="dataSource"
[sort]="sort"
>
<thead class="datatable-header">
<tr>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header.field"
[disableSort]="header.disableSort"
scope="col"
>
{{ header.label | titlecase }}
</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody class="datatable-body">
<tr
*ngIf="addRow"
[ngClass]="{ 'edited-row': addRow }"
scope="row"
cdkTrapFocus
cdkTrapFocusAutoCapture="true"
>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.company"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.address"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.city"
/>
</mdb-form-control>
</td>
<td>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="addNewRow()"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="discardNewRow()"
>
<i class="fa fa-ban"></i>
</button>
</td>
</tr>
<tr
*ngFor="let data of table.data; let index = index"
scope="row"
[cdkTrapFocus]="editElementIndex === index"
[cdkTrapFocusAutoCapture]="editElementIndex === index"
[ngClass]="{ 'edited-row': editElementIndex === index }"
>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.company }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.company"
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.address }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.address"
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.city }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.city"
/>
</mdb-form-control>
</ng-container>
</td>
<td>
<ng-container
*ngIf="editElementIndex === -1 || editElementIndex !== index"
>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark edit-button"
(click)="onEditClick(index)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-edit"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark delete-button"
(click)="onDeleteClick(data)"
[disabled]="
addRow ||
(editElementIndex !== -1 && editElementIndex !== index)
"
>
<i class="far fa-trash-alt"></i>
</button>
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="editElementIndex = -1"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="onDiscardEdit(index)"
>
<i class="fa fa-ban"></i>
</button>
</ng-container>
</td>
</tr>
</tbody>
</table>
</div>
import { Component, ViewChild } from '@angular/core';
import { MdbTableDirective } from 'mdb-angular-ui-kit/table';
export interface Person {
company: string;
address: string;
city: string;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('table') table!: MdbTableDirective<Person>;
editElementIndex = -1;
addRow = false;
mBLoaded = false;
barkleyAndClarkLoaded = false;
dAndDIncLoaded = false;
thomasAndCoLoaded = false;
newRow: Person = {
company: '',
address: '',
city: '',
};
editRow: Person = {
company: '',
address: '',
city: '',
};
headers = [
{ label: 'Company', field: 'company', disableSort: false },
{ label: 'Address', field: 'address', disableSort: false },
{ label: 'City', field: 'city', disableSort: false },
];
dataSource: Person[] = [
{ company: 'Smith & Johnson', address: 'Park Lane 2', city: 'London' },
{ company: 'P.J. Company', address: 'Oak Street 7', city: 'Aberdeen' },
{
company: 'Food & Wine',
address: 'Netherhall Gardens 3',
city: 'Hampstead',
},
{ company: 'IT Service', address: 'Warwick Road 14', city: 'London' },
{
company: 'A. Jonson Gallery',
address: 'Oaklands Avenue 2',
city: 'London',
},
{ company: 'F.A. Architects', address: 'Frognal Way 7', city: 'Hampstead' },
];
constructor() {}
search(event: Event): void {
const searchTerm = (event.target as HTMLInputElement).value;
this.table.search(searchTerm);
}
addNewRow(): void {
this.dataSource = [...this.dataSource, { ...this.newRow }];
this.newRow.company = '';
this.newRow.address = '';
this.newRow.city = 'null';
this.addRow = false;
}
discardNewRow(): void {
this.newRow.company = '';
this.newRow.address = '';
this.newRow.city = 'null';
this.addRow = false;
}
onEditClick(index: number): void {
this.editElementIndex = index;
this.editRow = { ...this.table.data[index] };
}
onDiscardEdit(index: number): void {
this.editElementIndex = -1;
this.table.data[index] = { ...this.editRow };
}
onDeleteClick(data: Person) {
const index = this.dataSource.indexOf(data);
this.dataSource.splice(index, 1);
this.dataSource = [...this.dataSource];
}
loadMB(): void {
const row = {
company: 'M.B.',
address: '5 Avenue 26',
city: 'New York',
};
this.mBLoaded = true;
this.addRow = true;
this.newRow = row;
}
loadBarkleyAndClark(): void {
const row = {
company: 'Berkley & Clark',
address: '43th Street 12',
city: 'New York',
};
this.barkleyAndClarkLoaded = true;
this.addRow = true;
this.newRow = row;
}
loadDAndDInc(): void {
const row = {
company: 'D&D Inc.',
address: '14 Street 67',
city: 'New York',
};
this.dAndDIncLoaded = true;
this.addRow = true;
this.newRow = row;
}
loadThomasAndCo(): void {
const row = {
company: 'Thomas & Co.',
address: '2 Avenue 54',
city: 'New York',
};
this.thomasAndCoLoaded = true;
this.addRow = true;
this.newRow = row;
}
}
Notifications
Note: This example use Alerts Remember to import them.
<div class="d-flex justify-content-end mb-4">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
id="search-input"
[disabled]="addRow || editElementIndex !== -1"
(keyup)="search($event)"
/>
<label mdbLabel class="form-label" for="search-input">Search</label>
</mdb-form-control>
<button
mdbRipple
class="btn btn-primary btn-sm ms-3"
[disabled]="editElementIndex !== -1"
(click)="addRow = true"
>
<i class="fa fa-plus"></i>
</button>
</div>
<hr />
<div
class="datatable table-editor mt-4"
[ngClass]="{
'edited-table': addRow || editElementIndex !== -1
}"
>
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sort="mdbTableSort"
[dataSource]="dataSource"
[sort]="sort"
[pagination]="pagination"
>
<thead class="datatable-header">
<tr>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header.field"
[disableSort]="header.disableSort"
scope="col"
>
{{ header.label | titlecase }}
</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody class="datatable-body">
<tr
*ngIf="addRow"
[ngClass]="{ 'edited-row': addRow }"
scope="row"
cdkTrapFocus
cdkTrapFocusAutoCapture="true"
>
<td>
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="newRow.company"
/>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<mdb-select [(ngModel)]="newRow.office">
<mdb-option
*ngFor="let option of options"
[value]="option.value"
>{{ option.label }}</mdb-option
>
</mdb-select>
</mdb-form-control>
</td>
<td>
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="newRow.employees"
/>
</mdb-form-control>
</td>
<td>
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
[(ngModel)]="newRow.international"
/>
</div>
</td>
<td>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="addNewRow()"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="discardNewRow()"
>
<i class="fa fa-ban"></i>
</button>
</td>
</tr>
<tr
*ngFor="let data of table.data; let index = index"
scope="row"
[cdkTrapFocus]="editElementIndex === index"
[cdkTrapFocusAutoCapture]="editElementIndex === index"
[ngClass]="{ 'edited-row': editElementIndex === index }"
>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.company }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="text"
class="form-control"
[(ngModel)]="data.company"
/>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.office }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<mdb-select [(ngModel)]="data.office">
<mdb-option
*ngFor="let option of options"
[value]="option.value"
>{{ option.label }}</mdb-option
>
</mdb-select>
</mdb-form-control>
</ng-container>
</td>
<td style="min-width: 250px; max-width: 250px">
<ng-container *ngIf="editElementIndex !== index">
{{ data.employees }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<mdb-form-control>
<input
mdbInput
type="number"
class="form-control"
[(ngModel)]="data.employees"
/>
</mdb-form-control>
</ng-container>
</td>
<td>
<ng-container *ngIf="editElementIndex !== index">
{{ data.international }}
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<div class="form-check ms-1 mt-1">
<input
mdbCheckbox
class="form-check-input"
type="checkbox"
[(ngModel)]="data.international"
/>
</div>
</ng-container>
</td>
<td>
<ng-container
*ngIf="editElementIndex === -1 || editElementIndex !== index"
>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark edit-button"
(click)="onEditClick(index)"
[disabled]="editElementIndex !== -1 && editElementIndex !== index"
>
<i class="far fa-edit"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark delete-button"
(click)="onDeleteClick(data)"
[disabled]="editElementIndex !== -1 && editElementIndex !== index"
>
<i class="far fa-trash-alt"></i>
</button>
</ng-container>
<ng-container *ngIf="editElementIndex === index">
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-dark save-button"
(click)="onSaveClick(data)"
>
<i class="fa fa-check"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-dark discard-button"
(click)="onDiscardEdit(index)"
>
<i class="fa fa-ban"></i>
</button>
</ng-container>
</td>
</tr>
</tbody>
</table>
<mdb-table-pagination
#pagination
[entries]="5"
[disabled]="addRow || editElementIndex !== -1"
></mdb-table-pagination>
</div>
import { Component, ViewChild } from '@angular/core';
import {
MdbNotificationService,
MdbNotificationRef,
} from 'mdb-angular-ui-kit/notification';
import { MdbTableDirective } from 'mdb-angular-ui-kit/table';
import { NotificationComponent } from './notification.component';
export interface Person {
company: string;
office: string;
employees: number | null;
international: boolean;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('table') table!: MdbTableDirective<Person>;
notificationRef: MdbNotificationRef<NotificationComponent> | null = null;
editElementIndex = -1;
addRow = false;
newRow: Person = {
company: '',
office: 'Warsaw',
employees: 1,
international: false,
};
editRow: Person = {
company: '',
office: '',
employees: null,
international: false,
};
options = [
{ value: 'London', label: 'London' },
{ value: 'Warsaw', label: 'Warsaw' },
{ value: 'New York', label: 'New York' },
];
headers = [
{ label: 'Company', field: 'company', disableSort: false },
{ label: 'Office', field: 'office', disableSort: true },
{ label: 'Employees', field: 'employees', disableSort: false },
{ label: 'International', field: 'international', disableSort: false },
];
dataSource: Person[] = [
{
company: 'Smith & Johnson',
office: 'London',
employees: 30,
international: true,
},
{
company: 'P.J. Company',
office: 'London',
employees: 80,
international: false,
},
{
company: 'Food & Wine',
office: 'London',
employees: 12,
international: false,
},
{
company: 'IT Service',
office: 'London',
employees: 17,
international: false,
},
{
company: 'A. Jonson Gallery',
office: 'London',
employees: 4,
international: false,
},
{
company: 'F.A. Architects',
office: 'London',
employees: 4,
international: false,
},
];
constructor(private notificationService: MdbNotificationService) {}
search(event: Event): void {
const searchTerm = (event.target as HTMLInputElement).value;
this.table.search(searchTerm);
}
addNewRow(): void {
this.dataSource = [...this.dataSource, { ...this.newRow }];
this.openAlert(this.newRow, 'add');
this.newRow.company = '';
this.newRow.office = 'Warsaw';
this.newRow.employees = 1;
this.newRow.international = false;
this.addRow = false;
}
discardNewRow(): void {
this.newRow.company = '';
this.newRow.office = 'Warsaw';
this.newRow.employees = 1;
this.addRow = false;
}
onEditClick(index: number): void {
this.editElementIndex = index;
this.editRow = { ...this.table.data[index] };
}
onDiscardEdit(index: number): void {
this.editElementIndex = -1;
this.table.data[index] = { ...this.editRow };
}
onDeleteClick(data: Person): void {
const index = this.dataSource.indexOf(data);
this.dataSource.splice(index, 1);
this.dataSource = [...this.dataSource];
this.openAlert(data, 'delete');
}
onSaveClick(data: Person): void {
this.editElementIndex = -1;
this.openAlert(data, 'edit');
}
openAlert(data: Person, action: 'add' | 'delete' | 'edit'): void {
const options = {
action: action,
rowData: `${data.company} (${data.office})`,
};
this.notificationRef = this.notificationService.open(
NotificationComponent,
{ data: options, autohide: true, delay: 1000 }
);
}
}
<div class="alert alert-{{ color }}" role="alert">
<strong>{{ actionText }}</strong> {{ rowData }}
</div>
import { Component, OnInit } from '@angular/core';
import { MdbNotificationRef } from 'mdb-angular-ui-kit/notification';
@Component({
selector: 'app-notification',
templateUrl: './notification.component.html',
})
export class NotificationComponent implements OnInit {
action: 'add' | 'delete' | 'edit' | null = null;
rowData: string | null = null;
color: string | null = null;
actionText: string | null = null;
constructor(
public notificationRef: MdbNotificationRef<NotificationComponent>
) {}
ngOnInit(): void {
switch (this.action) {
case 'add':
this.color = 'success';
this.actionText = 'New entry:';
break;
case 'delete':
this.color = 'danger';
this.actionText = 'Deleted entry:';
break;
case 'edit':
this.color = 'primary';
this.actionText = 'Updated entry:';
break;
default:
break;
}
}
}
Dark
Note: This example use Modal. Remember to import them.
Company | Address | Employees |
---|---|---|
Smith & Johnson | Park Lane 2, London | 30 |
P.J. Company | Oak Street 7, Aberdeen | 80 |
Food & Wine | Netherhall Gardens 3, Hampstead | 12 |
IT Service | Warwick Road 14, London | 17 |
A. Jonson Gallery | Oaklands Avenue 2, London | 4 |
F.A. Architects | Frognal Way 7, Hampstead | 4 |
<section class="border p-4 mb-4 bg-dark">
<div class="d-flex justify-content-end mb-4">
<mdb-form-control class="form-white">
<input
mdbInput
type="text"
class="form-control"
id="search-input"
(keyup)="search($event)"
/>
<label mdbLabel class="form-label" for="search-input">Search</label>
</mdb-form-control>
<button
mdbRipple
class="btn btn-outline-light btn-sm ms-3"
(click)="openModal('add')"
>
<i class="fa fa-plus"></i>
</button>
</div>
<hr />
<div
class="datatable table-editor bg-dark datatable-dark text-white border-white mt-4"
>
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sort="mdbTableSort"
[dataSource]="dataSource"
[sort]="sort"
[pagination]="pagination"
>
<thead class="datatable-header text-white">
<tr>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header.field"
[disableSort]="header.disableSort"
scope="col"
>
{{ header.label | titlecase }}
</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody class="datatable-body text-white">
<tr *ngFor="let data of table.data; let index = index" scope="row">
<td style="min-width: 250px; max-width: 250px">
{{ data.company }}
</td>
<td style="min-width: 250px; max-width: 250px">
{{ data.address }}
</td>
<td style="min-width: 250px; max-width: 250px">
{{ data.employees }}
</td>
<td>
<button
class="me-2 m-0 p-0 shadow-0 btn btn-lg text-light edit-button"
(click)="openModal('edit', data)"
>
<i class="far fa-edit"></i>
</button>
<button
class="m-0 p-0 shadow-0 btn btn-lg text-light delete-button"
(click)="onDeleteClick(data)"
>
<i class="far fa-trash-alt"></i>
</button>
</td>
</tr>
</tbody>
</table>
<mdb-table-pagination #pagination [entries]="5"></mdb-table-pagination>
</div>
</section>
import { Component, ViewChild } from '@angular/core';
import { MdbModalRef, MdbModalService } from 'mdb-angular-ui-kit/modal';
import { MdbTableDirective } from 'mdb-angular-ui-kit/table';
import { ModalComponent } from './modal.component';
export interface Person {
company: string;
address: string;
employees: number | null;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('table') table!: MdbTableDirective<Person>;
modalRef: MdbModalRef<ModalComponent> | null = null;
headers = [
{ label: 'Company', field: 'company', disableSort: false },
{ label: 'Address', field: 'address', disableSort: false },
{ label: 'Employees', field: 'employees', disableSort: false },
];
dataSource: Person[] = [
{
company: 'Smith & Johnson',
address: 'Park Lane 2, London',
employees: 30,
},
{
company: 'P.J. Company',
address: 'Oak Street 7, Aberdeen',
employees: 80,
},
{
company: 'Food & Wine',
address: 'Netherhall Gardens 3, Hampstead',
employees: 12,
},
{
company: 'IT Service',
address: 'Warwick Road 14, London ',
employees: 17,
},
{
company: 'A. Jonson Gallery',
address: 'Oaklands Avenue 2, London ',
employees: 4,
},
{
company: 'F.A. Architects',
address: 'Frognal Way 7, Hampstead ',
employees: 4,
},
];
constructor(private modalService: MdbModalService) {}
search(event: Event): void {
const searchTerm = (event.target as HTMLInputElement).value;
this.table.search(searchTerm);
}
openModal(mode: 'add' | 'edit', data?: Person): void {
this.modalRef = this.modalService.open(ModalComponent, {
data: {
modalTitle: mode === 'edit' ? 'Edit item' : 'New item',
company: data ? data.company : '',
address: data ? data.address : '',
employees: data ? data.employees : null,
},
});
this.modalRef.onClose.subscribe((modalData: Person) => {
if (!modalData) {
return;
}
if (mode === 'add') {
this.dataSource = [...this.dataSource, { ...modalData }];
} else if (mode === 'edit' && data) {
const index = this.dataSource.indexOf(data);
this.dataSource[index] = modalData;
this.dataSource = [...this.dataSource];
}
});
}
onDeleteClick(data: Person): void {
const index = this.dataSource.indexOf(data);
this.dataSource.splice(index, 1);
this.dataSource = [...this.dataSource];
}
}
<div class="modal-header bg-dark text-white">
<h5 class="modal-title" id="exampleModalLabel">{{ modalTitle }}</h5>
</div>
<div class="modal-body bg-dark text-white">
<div class="my-4 table-editor_input-wrapper">
<mdb-form-control class="form-white">
<input
mdbInput
type="text"
id="company-input"
class="form-control"
[(ngModel)]="company"
/>
<label mdbLabel class="form-label" for="company-input">Company</label>
</mdb-form-control>
</div>
<div class="my-4 table-editor_input-wrapper">
<mdb-form-control class="form-white">
<input
mdbInput
type="text"
id="address-input"
class="form-control"
[(ngModel)]="address"
/>
<label mdbLabel class="form-label" for="address-input">Address</label>
</mdb-form-control>
</div>
<div class="my-4 table-editor_input-wrapper">
<mdb-form-control class="form-white">
<input
mdbInput
type="number"
id="employees-input"
class="form-control"
[(ngModel)]="employees"
/>
<label mdbLabel class="form-label" for="employees-input">Employees</label>
</mdb-form-control>
</div>
</div>
<div class="modal-footer bg-dark text-white">
<button
type="button"
class="shadow-0 btn btn-md btn-outline-light"
(click)="modalRef.close()"
>
Cancel
</button>
<button
type="button"
class="shadow-0 btn btn-md btn-light"
(click)="saveData()"
>
Save
</button>
</div>
import { Component, OnInit } from '@angular/core';
import { MdbModalRef } from 'mdb-angular-ui-kit/modal';
@Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
})
export class ModalComponent implements OnInit {
modalTitle: string | null = null;
company: string | null = null;
address: string | null = null;
employees: string | null = null;
options = [
{ value: 'London', label: 'London' },
{ value: 'Warsaw', label: 'Warsaw' },
{ value: 'New York', label: 'New York' },
];
constructor(public modalRef: MdbModalRef<ModalComponent>) {}
ngOnInit(): void {}
saveData(): void {
const closeMessage = {
company: this.company,
employees: this.employees,
address: this.address,
};
this.modalRef.close(closeMessage);
}
}
Table editor - API
Import
import { MdbTableModule } from 'mdb-angular-ui-kit/table';
import { MdbFormsModule } from 'mdb-angular-ui-kit/forms';
import { FormsModule } from '@angular/forms';
import { A11yModule } from '@angular/cdk/a11y';
import { MdbSelectModule } from 'mdb-angular-ui-kit/select'; // For examples with Select
import { MdbModalModule } from 'mdb-angular-ui-kit/modal'; // For examples with Modal
import { MdbNotificationModule } from 'mdb-angular-ui-kit/notification'; // For examples with Notification
import { MdbPopconfirmModule } from 'mdb-angular-ui-kit/popconfirm'; // For examples with Popconfirm
...
@NgModule({
...
imports: [
MdbTableModule,
MdbFormsModule,
FormsModule,
A11yModule,
MdbSelectModule, // For examples with Select
MdbModalModule, // For examples with Modal
MdbNotificationModule, // For examples with Notification
MdbPopconfirmModule // For examples with Popconfirm
],
...
})