Nice to have
right hand of the sort un-down icon, between column, add an vertical left-right line icon, it will show icon when mouse hover on the column border line
NO
Providing a StackBlitz/Plunker (or similar) is the best way to get the team to see your issue.
Plunker starter (using on @master
): https://goo.gl/uDmqyY
StackBlitz starter (using latest npm
release): https://goo.gl/wwnhMV
With sort/paging and html5 content edit, we can easily do grid edit now, even without cdk grid. But column resize is pain, we need add css separately.
5
group by column feature can implement via embedded html table
I'd like to see this too. It's listed as a 'future enhancement' here
Is there any timeline about the availability of this feature?
@palarnab There's currently no timeline for this feature but we'd happily accept any community contributions to help us get this in. We are currently looking into CDK drag-and-drop support which might be useful for this request
since the drag and drop feature is in beta now, are there any updates on this issue? It seems like this is a pretty core feature for any data table api.
Also, are there any current workarounds or known methods to implement this in Material 6, while the feature is in development?
We hope they add this feature and very soon! Unfortunately, not having this feature is a deal-breaker for us so we'll have to use 3rd party tables until the Angular team or contributors add this. Any updates on a timeline?
@maintainers
I implemented the column resizing for a private project.
Unluckily I don't have time to propose a PR for this but I can help lending the code if you want a base/some ideas.
I would love to see this feature added to the datatable component.
@IlCallo
Could you kindly share your implementation, only, of course, if you are not under a NDA?
I can share something but right now I'm a bit on a hurry to finish a project. I'll try to disclose something ASAP but I can't give any assurance about when.
I'll try at least to provide some insight in some days
Here's the code I used.
You'll probably need to take into account the added pixels of the resizer when styling resizable cells.
If something is not clear, just drop here a question, but I hope comments will help you.
If you have suggestion about how to improve it, I'm interested to hear them :)
Edit: added imports.
Note that:
CoerceBoolean
is a decorator that automatically applies the coerceBooleanProperty
method from @angular/cdk
to the propertyBindObservable
is this very interesting decoratoruntilDestroyed
is this useful RxJS operatorcell-resizer.component.ts
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
HostBinding,
HostListener,
Input,
OnDestroy,
OnInit,
Output,
} from '@angular/core';
import { CoerceBoolean } from '<private decorator>';
import { BindObservable } from 'bind-observable';
import { untilDestroyed } from 'ngx-take-until-destroy';
import { fromEvent, Observable, Subscription } from 'rxjs';
import { skip } from 'rxjs/operators';
@Component({
selector: 'cell-resizer',
template: '',
styleUrls: ['./cell-resizer.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CellResizerComponent implements OnInit, OnDestroy {
@Input() private minWidth = 150;
@HostBinding('class.disabled') @Input() @CoerceBoolean() private disabled = false;
@Input()
public get width(): number {
return this._width;
}
// This is needed in case the width given by the server is less than the minimum width
// At CSS level this is enforced by the 'min-width' property
public set width(value: number) {
this._width = Math.max(value, this.minWidth);
}
private _width!: number;
@Output() public resized = new EventEmitter<number>();
@BindObservable() private isResizing = false;
private isResizing$!: Observable<boolean>;
@Output() public resizing = new EventEmitter<boolean>();
private dragSubscription?: Subscription;
public ngOnInit(): void {
this.isResizing$
.pipe(
// Skip default value
skip(1),
untilDestroyed(this)
)
.subscribe(isResizing => {
this.resizing.emit(isResizing);
if (isResizing) {
// We must use arrow function to avoid losing the context,
// we cannot pass directly the functions references
this.dragSubscription = fromEvent<MouseEvent>(window.document, 'mousemove')
.pipe(untilDestroyed(this))
.subscribe(event => this.resizeColumn(event));
this.dragSubscription.add(
fromEvent(window.document, 'mouseup')
.pipe(untilDestroyed(this))
.subscribe(() => this.stopResizig())
);
} else {
// When resize finishes, we emit one last "resized" event for which
// the corresponding "isResizing" value will be false.
// This can be used to detect which is the final resizing event
// and ignore the others
this.resized.emit(this.width);
if (this.dragSubscription) {
this.dragSubscription.unsubscribe();
}
}
});
}
// We could not put a @HostListener('mousemove', ['$event']) on the resizer itself because
// the movement on X axis easily exceed the resizer size,
// resulting in the action being interrupted
// We could not use @HostListener('document:mousemove', ['$event']) either because there is no way
// to start&stop it imperatively and mousemove causes global change detection to fire every pixel
// if put at document level, blocking the UI when there are a lot of things to render
// We resolved using Observables from events and subscribing/unsubscribing when resizing
// TODO check again when HostListener can be start&stopped
// See https://github.com/angular/angular/issues/7626
private resizeColumn(event: MouseEvent) {
const newWidth = this.width + event.movementX;
if (newWidth >= this.minWidth) {
this.resized.emit(newWidth);
}
// Prevent text selection while resizing
event.preventDefault();
}
// Same problems that mousemove listener have
private stopResizig() {
this.isResizing = false;
}
// isResizing can be set to true only when the component is not disabled
@HostListener('mousedown')
private startResizing() {
this.isResizing = !this.disabled;
}
// Must be present for AOT compilation to work, even if empty
// Otherwise 'ng build --prod' will optimize away any calls to ngOnDestroy,
// even if the method is added by the untilDestroyed operator
public ngOnDestroy() {}
}
cell-resizer.component.scss
:host {
border-left: 1px solid white;
border-right: 1px solid white;
cursor: col-resize;
display: block;
height: inherit;
min-height: inherit;
min-width: 2px;
&.disabled {
cursor: default;
}
}
Usage
Inside the component logic
interface ColumnModel {
title: string;
width: number;
}
column: ColumnModel = {
title: 'Title',
width: 150
}
isResizing = false;
columnResized(column: ColumnModel, width: number): void {
column.width = width;
}
Inside the template
<mat-header-cell class="cell--resizable" *matHeaderCellDef [style.flex-basis]="column.width + 'px'">
<span>{{ column.title }}</span>
<cell-resizer
[width]="column.width"
(resized)="columnResized(column, $event)"
(resizing)="isResizing = $event"
></cell-resizer>
</mat-header-cell>
/*
[1] The minimum width must be calculated including the padding
[2] Flex-basis is set to the minimum width by default, shrink and growth are disabled,
implentation is supposed to bind the calculated width to flex-basis property
*/
.mat-header-cell,
.mat-cell {
&.cell--resizable {
box-sizing: border-box; // [1]
flex: 0 0 150px; // [2]
min-width: 150px; // [1]
}
}
Hi @IlCallo,
Could you share the imports for the property decorators you use.
Also, I defined a custom column data for this issue and in columnResized(column, $event) method I update the widths based on the event. The flex-basis is updating, but the column doesn't resize. And with the scss you gave the cell-resizer within the header is not displayed properly it is not visible. Would you like to share the implementation with the mat-table too so we can see the whole usage.
I edited the previous post to include imports.
You are not required to use flex-basis to manage cell width, I did it like this because I'm using table in flex-box mode, but it depends on the use case you have.
Share your code and/or some screenshots and I can check if I notice some errors, but yours seem a CSS problem to me
For everyone that also needs to implement resizable columns.
I followed the approach from @IlCallo and needed to add the following function in the component that uses the cell-resizer:
columnResized(element: any, event: any) {
console.log("Changing width for " + element + " to " + event + " px.");
var column = <HTMLInputElement>document.getElementById(element);
column.width = event;
}
The resizing is now working!
Yeah, I didn't added columnResized
implementation because it's domain-related.
I added a minimal example of the logic to the post with all the code.
For everyone that also needs to implement resizable columns.
I followed the approach from @IlCallo and needed to add the following function in the component that uses the cell-resizer:columnResized(element: any, event: any) { console.log("Changing width for " + element + " to " + event + " px."); var column = <HTMLInputElement>document.getElementById(element); column.width = event; }
The resizing is now working!
Hi @IlCallo @lenngro
could you share how you handled import { CoerceBoolean } from '<private decorator>';
.. I am unable to follow that line.
I couldn't get it to work neither (although I did not try for too long), however not using that decorator does not prevent the resizer from working.
I couldn't get it to work neither (although I did not try for too long), however not using that decorator does not prevent the resizer from working.
@lenngro
Oh, I also tried without it, it doesnt seem to be problematic. Thank you.
although I got resizing working on header only.. below body not moving along..
It will be helpful if you could share your html and columnresize function?
CoerceBoolean is a decorator that automatically applies the coerceBooleanProperty method from @angular/cdk to the property
That decorator is just an helper custom decorator I did by myself, of course you cannot follow it 馃槄
You can just remove it or change it with the more classic coerceBooleanProperty method usage
Hi,
I do column resize with the angular-resizable-element lib.
Works with Angular material 7.
https://stackblitz.com/edit/mat-table-resize
install https://github.com/mattlewis92/angular-resizable-element
<mat-header-cell *matHeaderCellDef mat-sort-header
mwlResizable [enableGhostResize]="true"
(resizeEnd)="onResizeEnd($event, column)"
[resizeEdges]="{bottom: false, right: true, top: false, left: true}">
{{ column | titlecase }}
</mat-header-cell>
mwlResizable {
box-sizing: border-box;
}
mat-cell,
mat-footer-cell,
mat-header-cell {
width: 200px;
word-break: break-all;
flex: none; // important : dont be flex
display: block;
}
onResizeEnd(event: ResizeEvent, columnName): void {
if (event.edges.right) {
const cssValue = event.rectangle.width + 'px';
const columnElts = document.getElementsByClassName('mat-column-' + columnName);
for (let i = 0; i < columnElts.length; i++) {
const currentEl = columnElts[i] as HTMLDivElement;
currentEl.style.width = cssValue;
}
}
}
full source code : https://stackblitz.com/edit/mat-table-resize
Did some search and get the material table column resizing working.
Code is here: https://github.com/lujian98/Angular-material-table-Resize
Did some search and get the material table column resizing working.
Code is here: https://github.com/lujian98/Angular-material-table-Resize
i use this solution it is perfect thanks ;)
only one issue - when using with mattable with matsort / sort header
when after column resize - sorting is happening... is there any way to prevent sort on resize using this solution ? thanks !
@d00lar Can you add event.stopPropagation();
to see if this will prevent sort while resize column?
yes i checked - still sorting - i think it is triggered berofe on first click but happening after mouse up or something
i added title of column into span element and assigned mat-sort-header into this span - it is some override to this - now i can resize by clicking anywhere but sort only on clicking directly into center (this span) this way it is not sorting if resizing based on click not on this span with text ... not perfect but works ;P
Any Updates on a stable solution yet?
Did some search and get the material table column resizing working.
Code is here: https://github.com/lujian98/Angular-material-table-Resize
Demo at: https://stackblitz.com/edit/angular-rtfc5vi use this solution it is perfect thanks ;)
only one issue - when using with mattable with matsort / sort header
when after column resize - sorting is happening... is there any way to prevent sort on resize using this solution ? thanks !
Hi there, I am wondering do you combine the resizing with the reordering ? they seem to interfere each other
i added title of column into span element and assigned mat-sort-header into this span - it is some override to this - now i can resize by clicking anywhere but sort only on clicking directly into center (this span) this way it is not sorting if resizing based on click not on this span with text ... not perfect but works ;P
Could you please elaborate it in detail how you do it, i add the mat-sort-header
inside the unfortunately, it does not work and can not be confined in the center of cell
Most helpful comment
Did some search and get the material table column resizing working.
Code is here: https://github.com/lujian98/Angular-material-table-Resize
Demo at: https://stackblitz.com/edit/angular-rtfc5v