Angular material dispone de una componente para mostrar datos en una tabla.
Mostrar un listado de artículos (codigo, descripción y precio) mediante la componente mat-table.
Permitir borrar y agregar artículos.
Crearemos primero el proyecto
ng new proyecto027
Procedemos a instalar todas las dependencias de Angular Material ayudados por Angular CLI mediante el comando 'add':
ng add @angular/material
Modificamos el archivo 'app.module.ts' donde debemos importar MatTableModule, MatInputModule, MatButtonModule y FormsModule :
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatTableModule } from '@angular/material/table';
import {FormsModule} from '@angular/forms';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
MatTableModule,
MatInputModule,
MatButtonModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Modificamos el archivo 'app.component.ts' con la lógica de nuestra componente:
import { Component, ViewChild } from '@angular/core';
import { MatTable } from '@angular/material/table';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
columnas: string[] = ['codigo', 'descripcion', 'precio', 'borrar'];
datos: Articulo[] = [new Articulo(1, 'papas', 55),
new Articulo(2, 'manzanas', 53),
new Articulo(3, 'naranjas', 25),
];
articuloselect: Articulo = new Articulo(0, "", 0);
@ViewChild(MatTable) tabla1!: MatTable<Articulo>;
borrarFila(cod: number) {
if (confirm("Realmente quiere borrarlo?")) {
this.datos.splice(cod, 1);
this.tabla1.renderRows();
}
}
agregar() {
this.datos.push(new Articulo(this.articuloselect.codigo, this.articuloselect.descripcion, this.articuloselect.precio));
this.tabla1.renderRows();
this.articuloselect = new Articulo(0, "", 0);
}
}
export class Articulo {
constructor(public codigo: number, public descripcion: string, public precio: number) {
}
}
En este archivo también importamos la clase MatTable debido a que debemos obtener una referencia de la componente hija que definimos en:
@ViewChild(MatTable) tabla1: MatTable<Articulo>;
Luego mediante la variable tabla1 podemos llamar a métodos del objeto mat-table.
El atributo columna almacena los nombres con que se inician las propiedades matColumnDef de cada columna de la tabla:
columnas: string[] = ['codigo', 'descripcion', 'precio', 'borrar'];
La clase 'Articulo' se la declaró después de la clase 'AppComponent' (podemos perfectamente declararla en un archivo separado para mayor orden de nuestro código):
export class Articulo {
constructor(public codigo: number, public descripcion: string, public precio: number) {
}
}
El segundo atributo es un vector con componentes de tipo 'Articulo', lo iniciamos con 3 componentes (esta variable es la fuente de datos de la componente):
datos: Articulo[] = [new Articulo(1, 'papas', 55), new Articulo(2, 'manzanas', 53), new Articulo(3, 'naranjas', 25), ];
El atributo 'articuloselect' tiene la referencia de los datos que se cargan en el formulario:
articuloselect: Articulo = new Articulo(0, "", 0);
Los dos siguientes métodos permiten borrar y agregar una fila a la tabla:
borrarFila(cod: number) {
if (confirm("Realmente quiere borrarlo?")) {
this.datos.splice(cod, 1);
this.tabla1.renderRows();
}
}
agregar() {
this.datos.push(new Articulo(this.articuloselect.codigo, this.articuloselect.descripcion, this.articuloselect.precio));
this.tabla1.renderRows();
this.articuloselect = new Articulo(0, "", 0);
}
Codificamos la interfaz visual en el archivo 'app.component.html':
<table mat-table [dataSource]="datos" class="mat-elevation-z8" #tabla1>
<ng-container matColumnDef="codigo">
<th mat-header-cell *matHeaderCellDef> Código </th>
<td mat-cell *matCellDef="let articulo"> {{articulo.codigo}} </td>
</ng-container>
<ng-container matColumnDef="descripcion">
<th mat-header-cell *matHeaderCellDef> Descripción </th>
<td mat-cell *matCellDef="let articulo"> {{articulo.descripcion}} </td>
</ng-container>
<ng-container matColumnDef="precio">
<th mat-header-cell *matHeaderCellDef> Precio </th>
<td mat-cell *matCellDef="let articulo"> {{articulo.precio}} </td>
</ng-container>
<ng-container matColumnDef="borrar">
<th mat-header-cell *matHeaderCellDef> Borra? </th>
<td mat-cell *matCellDef="let j = index;">
<button mat-raised-button color="warn" focusable="false" (click)="borrarFila(j)">
Borra?
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnas"></tr>
<tr mat-row *matRowDef="let row; columns: columnas;"></tr>
</table>
<div class="contenedor">
<mat-form-field>
<input matInput [(ngModel)]="articuloselect.codigo" type="number" placeholder="Ingrese código">
</mat-form-field>
<mat-form-field>
<input matInput [(ngModel)]="articuloselect.descripcion" type="text" placeholder="Ingrese descripción">
</mat-form-field>
<mat-form-field>
<input matInput [(ngModel)]="articuloselect.precio" type="number" placeholder="Ingrese precio">
</mat-form-field>
<button mat-raised-button color="primary" (click)="agregar()">Agregar</button>
</div>
Cuando definimos la etiqueta 'table' especificamos el enlace de la propiedad '[dataSource]' con nuestro vector definido en la clase:
<table mat-table [dataSource]="datos" class="mat-elevation-z8" #tabla1>
Para las columnas definimos etiquetas 'ng-container' iniciando la propiedad 'matColumnDef' con alguna de las componentes del atributo 'columnas', también creamos el título de la columna como su contenido:
<ng-container matColumnDef="codigo">
<th mat-header-cell *matHeaderCellDef> Código </th>
<td mat-cell *matCellDef="let articulo"> {{articulo.codigo}} </td>
</ng-container>
La columna para borrar tiene una lógica distinta ya que debemos mostrar un botón el cual al ser presionado llama al método que elimina un elemento del vector y actualiza la tabla:
<ng-container matColumnDef="borrar">
<th mat-header-cell *matHeaderCellDef> Borra? </th>
<td mat-cell *matCellDef="let j = index;">
<button mat-raised-button color="warn" focusable="false" (click)="borrarFila(j)">
Borra?
</button>
</td>
</ng-container>
Luego tenemos el formulario, tema que ya hemos visto en conceptos anteriores:
<div class="contenedor">
<mat-form-field>
<input matInput [(ngModel)]="articuloselect.codigo" type="number" placeholder="Ingrese código">
</mat-form-field>
<mat-form-field>
<input matInput [(ngModel)]="articuloselect.descripcion" type="text" placeholder="Ingrese descripción">
</mat-form-field>
<mat-form-field>
<input matInput [(ngModel)]="articuloselect.precio" type="number" placeholder="Ingrese precio">
</mat-form-field>
<button mat-raised-button color="primary" (click)="agregar()">Agregar</button>
</div>
la hoja de estilo de la componente 'app.component.css':
table {
width: 90%;
margin:1rem auto;
}
.contenedor {
display: flex;
flex-direction: column;
margin:1rem auto;
max-width: 600px;
box-shadow: -1px 3px 66px 0px rgba(0,0,0,0.75);
padding: 1rem;
}
Si ejecutamos la aplicación tenemos como resultado:

Podemos probar esta aplicación en la web aquí.
Es muy importante cuando trabajamos con Angular Material tener la documentación oficial de esta librería de componentes. En lo referente a tablas debemos acceder a table.