Angular Material tables provide a sleek way to display data. However, users often want additional functionality like the ability to resize table columns for better control over data display. In this guide, we'll walk through the process of creating resizable columns in an Angular table using a custom directive. You'll learn how to set up the directive, style the resizer, and implement column resizing step-by-step.
Adding resizable columns to an Angular Material table involves creating a custom directive that listens to mouse events, allowing users to click and drag a column to adjust its width. This gives users flexibility, especially when dealing with large datasets, improving the user experience.
In this tutorial, we will:
Let’s dive into it.
First, ensure that your Angular project has Angular Material installed. If not, run the following command to add Angular Material to your project:
ng add @angular/material
Once Angular Material is installed, you can create a basic table using the following code.
HTML for the Table:
<div class="resizable-table"> <table mat-table [dataSource]="dataSource"> <ng-container *ngFor="let column of displayedColumns" [matColumnDef]="column"> <th mat-header-cell *matHeaderCellDef appColumnResize>{{ column }}</th> <td mat-cell *matCellDef="let element">{{ element[column] }}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> </div>
Here, we use mat-table from Angular Material to display a simple table. The appColumnResize directive is applied to the th (header) elements to make columns resizable.
Data for the Table:
import { Component, ViewEncapsulation } from '@angular/core'; export interface PeriodicElement { name: string; position: number; weight: number; symbol: string; } const ELEMENT_DATA: PeriodicElement[] = [ { position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' }, { position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' }, // ... add more data ]; @Component({ selector: 'table-basic-example', styleUrls: ['table-basic-example.scss'], templateUrl: 'table-basic-example.html', encapsulation: ViewEncapsulation.None, }) export class TableBasicExample { displayedColumns: string[] = ['position', 'name', 'weight', 'symbol']; dataSource = ELEMENT_DATA; }
The component includes data for the periodic elements, which we will display in the table.
Next, we’ll implement a custom Angular directive that enables resizing functionality for the table columns.
Directive Implementation:
import { Directive, ElementRef, Renderer2, NgZone, Input, OnInit, OnDestroy, } from '@angular/core'; import { fromEvent, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Directive({ selector: '[appColumnResize]', }) export class ColumnResizeDirective implements OnInit, OnDestroy { @Input() resizableTable: HTMLElement | null = null; private startX!: number; private startWidth!: number; private isResizing = false; private column: HTMLElement; private resizer!: HTMLElement; private destroy$ = new Subject<void>(); constructor( private el: ElementRef, private renderer: Renderer2, private zone: NgZone ) { this.column = this.el.nativeElement; } ngOnInit() { this.createResizer(); this.initializeResizeListener(); } private createResizer() { this.resizer = this.renderer.createElement('div'); this.renderer.addClass(this.resizer, 'column-resizer'); this.renderer.setStyle(this.resizer, 'position', 'absolute'); this.renderer.setStyle(this.resizer, 'right', '0'); this.renderer.setStyle(this.resizer, 'top', '0'); this.renderer.setStyle(this.resizer, 'width', '5px'); this.renderer.setStyle(this.resizer, 'cursor', 'col-resize'); this.renderer.appendChild(this.column, this.resizer); } private initializeResizeListener() { this.zone.runOutsideAngular(() => { fromEvent(this.resizer, 'mousedown') .pipe(takeUntil(this.destroy$)) .subscribe((event: MouseEvent) => this.onMouseDown(event)); fromEvent(document, 'mousemove') .pipe(takeUntil(this.destroy$)) .subscribe((event: MouseEvent) => this.onMouseMove(event)); fromEvent(document, 'mouseup') .pipe(takeUntil(this.destroy$)) .subscribe(() => this.onMouseUp()); }); } private onMouseDown(event: MouseEvent) { event.preventDefault(); this.isResizing = true; this.startX = event.pageX; this.startWidth = this.column.offsetWidth; } private onMouseMove(event: MouseEvent) { if (!this.isResizing) return; const width = this.startWidth + (event.pageX - this.startX); this.renderer.setStyle(this.column, 'width', `${width}px`); } private onMouseUp() { if (!this.isResizing) return; this.isResizing = false; } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } }
We need to style the resizer so users know it's draggable. Add the following CSS to your styles:
.resizable-table { th { position: relative; .column-resizer { position: absolute; top: 0; right: 0; bottom: 0; width: 10px; cursor: col-resize; z-index: 1; &:hover { border-right: 2px solid red; } } &.resizing { user-select: none; } } &.resizing { cursor: col-resize; user-select: none; } }
This CSS positions the resizer correctly, adds a hover effect, and changes the cursor to indicate resizability.
Now that the directive and styles are in place, try resizing the columns. You should be able to click on the resizer, drag it left or right, and dynamically adjust the width of each column.
Q: What happens if the resizable table is too wide?
A: The table will overflow and adjust based on the container's width. Ensure you add proper scroll behavior or container adjustments to handle large tables.
Q: Can I make specific columns non-resizable?
A: Yes, you can conditionally apply the appColumnResize directive to only specific columns by using Angular's built-in structural directives like *ngIf.
Q: Is this approach performance-friendly for large tables?
A: This solution works well for moderate-sized tables. However, for extremely large datasets, you may want to optimize further by using Angular's change detection strategy or a virtual scrolling mechanism.
By following this guide, you now have a fully functional resizable column feature for your Angular Material tables. This customization enhances the flexibility and usability of your tables, providing a better user experience. Happy coding!
위 내용은 Angular 테이블의 크기 조정 가능한 열 마스터하기: 개발자를 위한 단계별 가이드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!