Houd me bezig met het implementeren van een aangepaste Angular gegevens tabel component met sorteer- en pagineringsfuncties
description
Door deze prompt te volgen, ontwikkelen gebruikers een zeer functioneel gegevens tabel component dat de gegevenspresentatie en gebruikerservaring binnen hun Angular applicaties verbetert.
prompt
try_prompt
Help me een gegevens tabel component te maken in mijn Angular applicatie dat ondersteuning biedt voor dynamische gegevensbinding, sortering en paginering. Leg uit hoe je de component structureert, gegevensinvoer beheert en gebruikersinteracti ... more
generate_helper
...
ai_answers
provider: openai
model: gpt-4.1-nano
Zeker! Hier is een uitgebreide gids voor het maken van een flexibele gegevens tabel component in Angular die dynamische gegevensbinding, sortering en paginering ondersteunt.
### 1. Component structuur
**a. Maak een nieuwe component:**
```bash
ng generate component data-table
```
**b. Componentbestanden:**
- `data-table.component.ts`
- `data-table.component.html`
- `data-table.component.css`
---
### 2. gegevensinvoer beheren
Gebruik `@Input()` om de gegevens door te geven en definieer opties voor sortering en paginering.
```typescript
// data-table.component.ts
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'app-data-table',
templateUrl: './data-table.component.html',
styleUrls: ['./data-table.component.css']
})
export class DataTableComponent implements OnInit {
@Input() gegevens: any[] = [];
@Input() kolommen: string[] = [];
gesorteerdeGegevens: any[] = [];
sorteerKolom: string = '';
sorteerAsc: boolean = true;
pagina: number = 1;
itemsPerPagina: number = 5;
ngOnInit() {
this.gesorteerdeGegevens = [...this.gegevens];
}
// Methode voor sorteren
sorteer(kolom: string) {
if (this.sorteerKolom === kolom) {
this.sorteerAsc = !this.sorteerAsc;
} else {
this.sorteerKolom = kolom;
this.sorteerAsc = true;
}
this.gesorteerdeGegevens.sort((a, b) => {
const waardeA = a[kolom];
const waardeB = b[kolom];
if (waardeA < waardeB) return this.sorteerAsc ? -1 : 1;
if (waardeA > waardeB) return this.sorteerAsc ? 1 : -1;
return 0;
});
}
// Pagineregelingen
get paginagegevens() {
const start = (this.pagina - 1) * this.itemsPerPagina;
return this.gesorteerdeGegevens.slice(start, start + this.itemsPerPagina);
}
volgendePagina() {
if (this.pagina * this.itemsPerPagina < this.gesorteerdeGegevens.length) {
this.pagina++;
}
}
vorigePagina() {
if (this.pagina > 1) {
this.pagina--;
}
}
}
```
---
### 3. HTML sjabloon
Implementeer koppen met sorteerknoppen en paginabesturingen.
```html
<!-- data-table.component.html -->
<table>
<thead>
<tr>
<th *ngFor="let kolom van kolommen" (click)="sorteer(kolom)">
{{ kolom | titlecase }}
<span *ngIf="sorteerKolom === kolom">
{{ sorteerAsc ? '↑' : '↓' }}
</span>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let rij of paginagegevens">
<td *ngFor="let kolom of kolommen">
{{ rij[kolom] }}
</td>
</tr>
</tbody>
</table>
<!-- Paginering -->
<div class="paginatie">
<button (click)="vorigePagina()" [disabled]="pagina === 1">Vorige</button>
<span>Pagina {{ pagina }} van {{ Math.ceil(gesorteerdeGegevens.length / itemsPerPagina) }}</span>
<button (click)="volgendePagina()" [disabled]="pagina * itemsPerPagina >= gesorteerdeGegevens.length">Volgende</button>
</div>
```
---
### 4. Responsief ontwerp
Gebruik CSS Flexbox of media queries:
```css
/* data-table.component.css */
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 8px;
border: 1px solid #ddd;
text-align: left;
}
th {
cursor: pointer;
background-color: #f2f2f2;
}
@media (max-width: 600px) {
table, thead, tbody, th, td, tr {
display: block;
}
thead {
display: none;
}
tr {
margin-bottom: 15px;
}
td {
position: relative;
padding-left: 50%;
}
td::before {
position: absolute;
top: 8px;
left: 8px;
width: 45%;
padding-right: 10px;
white-space: nowrap;
font-weight: bold;
}
td:nth-of-type(1)::before { content: 'ID'; }
td:nth-of-type(2)::before { content: 'Naam'; }
td:nth-of-type(3)::before { content: 'Prijs'; }
}
```
---
### 5. Voorbeeldgebruik
In je hoofdcomponent:
```html
<app-data-table
[gegevens]="producten"
[kolommen]="['id', 'naam', 'prijs']">
</app-data-table>
```
En in de parent component:
```typescript
producten = [
{ id: 1, naam: 'Product A', prijs: 30 },
{ id: 2, naam: 'Product B', prijs: 50 },
// voeg meer data toe
];
```
---
### 6. Omgaan met verschillende gegevenstypen
- Numerieke waarden (zoals 'prijs') worden automatisch gesorteerd.
- Voor complexe typen of datums kun je custom sorteerfuncties toevoegen.
- Bijvoorbeeld, voor datums:
```typescript
// Pas sorteerfunctie aan
if (kolom === 'datum') {
this.gesorteerdeGegevens.sort((a, b) => {
const dateA = new Date(a[kolom]);
const dateB = new Date(b[kolom]);
return this.sorteerAsc ? dateA.getTime() - dateB.getTime() : dateB.getTime() - dateA.getTime();
});
} else {
// bestaande sorteerlogica
}
```
---
### Samenvatting
- **Structuur:** Maak een herbruikbare component met input voor gegevens en kolommen.
- **Gegevensbeheer:** Houd een interne kopie voor sortering en paginering.
- **Sortering:** Activeer door op koppen te klikken met visuele indicatoren.
- **Paginering:** Voer paginawijzigingen uit met knoppen en bereken de subset van gegevens.
- **Responsief ontwerp:** Gebruik CSS media queries voor mobiele weergave.
- **Uitbreiding:** Voeg functies toe voor sorteren op datums, tekst, getallen, en pas styling aan voor een betere gebruikerservaring.
Als je verdere hulp nodig hebt, laat het gerust weten!
provider: deepseek
model: deepseek-chat
Hier is een complete uitleg voor het maken van een gegevens tabel component in Angular:
## 1. Component Structuur
Eerst genereren we het component:
```bash
ng generate component data-table
```
**data-table.component.ts:**
```typescript
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
export interface ColumnDefinition {
key: string;
label: string;
sortable?: boolean;
dataType?: 'string' | 'number' | 'date' | 'currency';
}
@Component({
selector: 'app-data-table',
templateUrl: './data-table.component.html',
styleUrls: ['./data-table.component.css']
})
export class DataTableComponent implements OnChanges {
@Input() data: any[] = [];
@Input() columns: ColumnDefinition[] = [];
@Input() pageSize: number = 5;
@Input() currentPage: number = 1;
@Output() sortChange = new EventEmitter<{key: string, direction: string}>();
@Output() pageChange = new EventEmitter<number>();
sortedData: any[] = [];
totalPages: number = 1;
sortKey: string = '';
sortDirection: 'asc' | 'desc' = 'asc';
ngOnChanges(changes: SimpleChanges): void {
if (changes['data'] || changes['pageSize']) {
this.calculatePagination();
this.applySorting();
}
}
calculatePagination(): void {
this.totalPages = Math.ceil(this.data.length / this.pageSize);
this.applyPagination();
}
applyPagination(): void {
const startIndex = (this.currentPage - 1) * this.pageSize;
const endIndex = startIndex + this.pageSize;
this.sortedData = this.data.slice(startIndex, endIndex);
}
applySorting(): void {
if (!this.sortKey) {
this.applyPagination();
return;
}
const sorted = [...this.data].sort((a, b) => {
const aValue = a[this.sortKey];
const bValue = b[this.sortKey];
if (this.sortDirection === 'asc') {
return aValue < bValue ? -1 : aValue > bValue ? 1 : 0;
} else {
return aValue > bValue ? -1 : aValue < bValue ? 1 : 0;
}
});
const startIndex = (this.currentPage - 1) * this.pageSize;
const endIndex = startIndex + this.pageSize;
this.sortedData = sorted.slice(startIndex, endIndex);
}
onSort(column: ColumnDefinition): void {
if (!column.sortable) return;
if (this.sortKey === column.key) {
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
} else {
this.sortKey = column.key;
this.sortDirection = 'asc';
}
this.sortChange.emit({ key: this.sortKey, direction: this.sortDirection });
this.applySorting();
}
onPageChange(page: number): void {
if (page < 1 || page > this.totalPages) return;
this.currentPage = page;
this.pageChange.emit(page);
this.applySorting();
}
formatValue(value: any, dataType?: string): string {
switch (dataType) {
case 'currency':
return `€${value.toFixed(2)}`;
case 'number':
return value.toString();
case 'date':
return new Date(value).toLocaleDateString('nl-NL');
default:
return value;
}
}
}
```
## 2. Template (data-table.component.html)
```html
<div class="data-table-container">
<div class="table-responsive">
<table class="data-table">
<thead>
<tr>
<th *ngFor="let column of columns"
[class.sortable]="column.sortable"
[class.sorted]="sortKey === column.key"
(click)="onSort(column)">
{{ column.label }}
<span *ngIf="sortKey === column.key" class="sort-indicator">
{{ sortDirection === 'asc' ? '↑' : '↓' }}
</span>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of sortedData">
<td *ngFor="let column of columns">
{{ formatValue(item[column.key], column.dataType) }}
</td>
</tr>
<tr *ngIf="sortedData.length === 0">
<td [attr.colspan]="columns.length" class="no-data">
Geen gegevens beschikbaar
</td>
</tr>
</tbody>
</table>
</div>
<!-- Paginering -->
<div class="pagination-controls" *ngIf="totalPages > 1">
<button (click)="onPageChange(currentPage - 1)"
[disabled]="currentPage === 1"
class="pagination-btn">
Vorige
</button>
<span class="page-info">
Pagina {{ currentPage }} van {{ totalPages }}
</span>
<button (click)="onPageChange(currentPage + 1)"
[disabled]="currentPage === totalPages"
class="pagination-btn">
Volgende
</button>
</div>
</div>
```
## 3. Styling (data-table.component.css)
```css
.data-table-container {
width: 100%;
margin: 1rem 0;
}
.table-responsive {
overflow-x: auto;
}
.data-table {
width: 100%;
border-collapse: collapse;
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.data-table th,
.data-table td {
padding: 12px 16px;
text-align: left;
border-bottom: 1px solid #e0e0e0;
}
.data-table th {
background-color: #f5f5f5;
font-weight: 600;
cursor: default;
}
.data-table th.sortable {
cursor: pointer;
transition: background-color 0.2s;
}
.data-table th.sortable:hover {
background-color: #ebebeb;
}
.data-table th.sorted {
background-color: #e3f2fd;
color: #1976d2;
}
.sort-indicator {
margin-left: 8px;
font-weight: bold;
}
.no-data {
text-align: center;
color: #666;
font-style: italic;
padding: 2rem;
}
.pagination-controls {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
margin-top: 1rem;
padding: 1rem;
}
.pagination-btn {
padding: 8px 16px;
border: 1px solid #ddd;
background: white;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
}
.pagination-btn:hover:not(:disabled) {
background: #f5f5f5;
}
.pagination-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.page-info {
font-weight: 500;
}
/* Responsief ontwerp */
@media (max-width: 768px) {
.data-table th,
.data-table td {
padding: 8px 12px;
font-size: 14px;
}
.pagination-controls {
flex-direction: column;
gap: 0.5rem;
}
}
@media (max-width: 480px) {
.table-responsive {
font-size: 12px;
}
.data-table th,
.data-table td {
padding: 6px 8px;
}
}
```
## 4. Gebruik in Parent Component
**parent.component.ts:**
```typescript
import { Component } from '@angular/core';
import { ColumnDefinition } from '../data-table/data-table.component';
@Component({
selector: 'app-parent',
template: `
<app-data-table
[data]="productData"
[columns]="tableColumns"
[pageSize]="pageSize"
[currentPage]="currentPage"
(sortChange)="onSortChange($event)"
(pageChange)="onPageChange($event)">
</app-data-table>
`
})
export class ParentComponent {
productData = [
{ id: 1, naam: 'Product A', prijs: 30, voorraad: 100, aanmaakDatum: '2024-01-15' },
{ id: 2, naam: 'Product B', prijs: 50, voorraad: 75, aanmaakDatum: '2024-01-20' },
{ id: 3, naam: 'Product C', prijs: 25.99, voorraad: 150, aanmaakDatum: '2024-01-10' },
{ id: 4, naam: 'Product D', prijs: 99.99, voorraad: 25, aanmaakDatum: '2024-01-25' },
{ id: 5, naam: 'Product E', prijs: 15.5, voorraad: 200, aanmaakDatum: '2024-01-05' }
];
tableColumns: ColumnDefinition[] = [
{ key: 'id', label: 'ID', sortable: true, dataType: 'number' },
{ key: 'naam', label: 'Productnaam', sortable: true, dataType: 'string' },
{ key: 'prijs', label: 'Prijs', sortable: true, dataType: 'currency' },
{ key: 'voorraad', label: 'Voorraad', sortable: true, dataType: 'number' },
{ key: 'aanmaakDatum', label: 'Aanmaakdatum', sortable: true, dataType: 'date' }
];
pageSize = 3;
currentPage = 1;
onSortChange(sortEvent: {key: string, direction: string}): void {
console.log('Sorteren op:', sortEvent.key, 'richting:', sortEvent.direction);
// Hier kun je eventueel server-side sortering implementeren
}
onPageChange(page: number): void {
this.currentPage = page;
console.log('Pagina gewijzigd naar:', page);
// Hier kun je eventueel server-side paginering implementeren
}
}
```
## 5. Gegevenstype Ondersteuning
De component ondersteunt verschillende gegevenstypen:
- **String**: Standaard weergave
- **Number**: Numerieke weergave
- **Currency**: Euro formatting (€30.00)
- **Date**: Nederlands datumformaat (15-1-2024)
## 6. Responsief Ontwerp Features
- **Horizontaal scrollen** voor kleine schermen
- **Aanpasbare padding** op verschillende breakpoints
- **Flexibele paginering** die verticaal wordt op kleine schermen
- **Schalende font-groottes** voor betere leesbaarheid
Deze implementatie biedt een robuuste, herbruikbare tabel component die gemakkelijk kan worden uitgebreid met extra functionaliteit zoals filtering, rijselectie of inline editing.

