Updated on Kisan Patel
How to make a table with resizable columns with RxJS in Angular?
First, create resizable directive as follow:
ng g d resizable
resizable.directive.ts
import { DOCUMENT } from "@angular/common"; import { Directive, ElementRef, Inject, Output } from "@angular/core"; import { distinctUntilChanged, map, switchMap, takeUntil, tap } from "rxjs/operators"; import { fromEvent } from "rxjs"; @Directive({ selector: "[resizable]" }) export class ResizableDirective { @Output() readonly resizable = fromEvent<MouseEvent>( this.elementRef.nativeElement, "mousedown" ).pipe( tap(e => e.preventDefault()), switchMap(() => { const { width, right } = this.elementRef.nativeElement .closest("th") .getBoundingClientRect(); return fromEvent<MouseEvent>(this.documentRef, "mousemove").pipe( map(({ clientX }) => width + clientX - right), distinctUntilChanged(), takeUntil(fromEvent(this.documentRef, "mouseup")) ); }) ); constructor( @Inject(DOCUMENT) private readonly documentRef: Document, @Inject(ElementRef) private readonly elementRef: ElementRef<HTMLElement> ) {} }
Now, create resizable component as follow:
resizable.component.ts
import { Component, ElementRef, HostBinding } from "@angular/core"; @Component({ selector: "th[resizable]", templateUrl: "./resizable.component.html", styleUrls: ["./resizable.component.less"], }) export class ResizableComponent { @HostBinding("style.width.px") width: number | null = null; onResize(width: number) { this.width = width; } }
resizable.component.html
<div class="wrapper"> <div class="content"> <ng-content></ng-content> </div> <div class="bar" (resizable)="onResize($event)"></div> </div>
resizable.component.less
:host { &:last-child .bar { display: none; } } .wrapper { display: flex; justify-content: flex-end; } .content { flex: 1; } .bar { position: absolute; top: 0; bottom: 0; width: 2px; margin-left: 16px; justify-self: flex-end; border-left: 2px solid transparent; border-right: 2px solid transparent; background: blueviolet; background-clip: content-box; cursor: ew-resize; opacity: 0; transition: opacity .3s; &:hover, &:active { opacity: 1; } }
Now, use as follow:
app.component.ts
<h1>Resizable table demo</h1> <table> <thead> <tr> <th resizable>Member</th> <th resizable>Nickname</th> <th>Fate</th> </tr> </thead> <tbody> <tr *ngFor="let row of rows"> <td *ngFor="let cell of row">{{cell}}</td> </tr> </tbody> </table>