Angular material table: Dynamic sticky columns break the table - css

Dynamically adding a mix of sticky and non-sticky columns to mat-table seems to break it. You can see the demo here: https://stackblitz.com/edit/angular-mfxahi?file=src/app/table-sticky-columns-example.ts
I suspect that the issue is due to Angular not knowing the actual width of the content in the column, however setting width or min-width to .mat-header-cell, .mat-cell doesn't help. When inspecting the columns you can see that left CSS attribute is not set to correct value.
I cannot change the table to use static definitions as it is reused in different scenarios. Any idea how to fix this issue?

Instead of setting the width on .mat-header-cell or .mat-cell, set width and left on the columns which are sticky (.mat-column-<label>). In order for it to work, the left value needs to be set to at least the width of the previous column:
.mat-column-name {
width: 110px;
}
.mat-column-position {
width: 80px;
left: 110px !important;
}
Note: you need to use !important since left is set on .mat-header-cell and .mat-cell directly.
If you want to style the sticky columns more dynamically, you can add the styling to your column definition and then use it in the template:
const DEFINITIONS: ColumnDefintion[] = [
{label: 'name', sticky: true, style: {'width':'100px', 'left':'0px'}},
{label: 'position', sticky: true, style: {'width':'80px', 'left':'100px'}},
{label: 'weight'},
{label: 'symbol'},
]
<!-- ... -->
<ng-container *ngIf="colDef.sticky" [matColumnDef]="colDef.label" sticky>
<th mat-header-cell *matHeaderCellDef [ngStyle]="colDef.style">{{colDef.label}}</th>
<td mat-cell *matCellDef="let element" [ngStyle]="colDef.style">{{element[colDef.label]}}</td>
</ng-container>
<!-- ... -->
Working example: Stackblitz

i had the same problem it seems to be a general issue if you play with sticky and dynamic cols.
GitHub Link: https://github.com/angular/components/issues/15885
This worked for me:
#ViewChild(MatTable) table: MatTable<any>;
ngAfterViewChecked(): void {
if (this.table) {
this.table.updateStickyColumnStyles();
}
}
hope it works for you too.

Related

How to set Height of p-table to window height

Problem:
I'm trying to set the height of a prime p-table in angular. I already searched the net and found so many results but none worked so far (probably due to this problem beeing around for many years and changes to the framework disabled certain solutions).
I already tried two approaches the first is in the code below. The second is setting the height of the parent div of the p-table to innerWindowHeight and setting scrollheight of p-table to flex (doesn't work either).
Tools: Angular 14.2.0 and PrimeNG 14.1.1 in a fresh project
I have the following html code in app.component.html:
<div>
<p-table #table
(window:resize)="onResize()"
[value]="data"
[paginator]="true"
[showCurrentPageReport]="true"
[scrollable]="true"
[scrollHeight]="tableScrollHeight"
[rows]="10"
[rowsPerPageOptions]="rowsPerPage"
styleClass="p-datatable-gridlines p-datatable-striped p-datatable-sm"
currentPageReportTemplate="{first} to {last} of {totalRecords} records">
<ng-template pTemplate="header">
<tr>
<th>Date</th>
<th>ID</th>
<th>Description</th>
<th>Value</th>
<th>Tax</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-entry>
<tr>
<td>{{entry.date}}</td>
<td>{{entry.id}}</td>
<td>{{entry.description}}</td>
<td>{{entry.value}}</td>
<td>{{entry.tax}}</td>
</tr>
</ng-template>
</p-table>
</div>
And the following app.component.ts :
import {Component} from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Testapp';
data: any[];
tableScrollHeight: string = "700px";
rowsPerPage: number[] = [5, 10, 20, 50];
constructor() {
this.data = [];
let entry: any = {};
entry.description = "First entry";
this.data.push(entry);
}
onResize() {
this.tableScrollHeight = window.innerHeight + 'px';
}
}
Behaviour I want to implement:
What I want is, that the Paginator stays at the bottom of the window even if the table is empty or dosen't have enough entries to fill the window and that the table is scrollable (header staying at top) as soon as the table rows are bigger than the screen size.
To clarify what I want to acomplish here a screenshot how it looks:
How it looks right now
And here a screenshot how I want it to look:
What it should look like
Question:
Is it possible to acomplish this in a clean way?
Like suggested in the comment I added a stackblitz : https://angular-ivy-sfk7pw.stackblitz.io
Edit:
I found that if you set scrollHeight of table a div inside the table (generated from primeng) with class p-datatable-wrapper gets the style "max-height: XXXpx" where as XXX is the value from tableScrollHeight. I could probably write a CSS selector to change the style to min-width but that's probably not a good Idea since I would have to access the dom from the typscript file and search for the auto generated div.
Maybe you can try to add this style to your css/scss, but this is not a best practice.
.p-datatable-wrapper {
min-height: calc(100vh - 90px);
}
Note: 100vh is your screen height and 90px it's an example your pagination height.
That's it. I hope it can help.

p:datatable with scroll on content

I have a datatable with primefaces:
<p:dataTable var="wapsoplandtl" id="wapsoplandtlList" widgetVar="wapsoplandtlList" value="#{exportController.wapsoplandtls}"
paginator="true" rows="50" scrollable="true" scrollWidth="2500px;" styleClass="borderless"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {CurrentPageReport}"
currentPageReportTemplate="{startRecord} - {endRecord} of {totalRecords}" paginatorPosition="bottom"
rowsPerPageTemplate="10,25,50" rowKey="#{wapsoplandtl.dtlsys}">
and produce something like this:
As you can see, it has scrollwidth attribute, but the header got scrolled to the far right. I want only scroll the content of datatable, not the header and footer (paging). Can anyone help me?
This can be done by CSS only, forget about the scrollable attribute of the <p:datatable> component, apparently it will always overflow the whole table, and not just the content.
In this case, do the following:
Remove the scrollable and scrollWidth attribute from your <p:datatable> component;
Include another CSS class (any name, but keep this name to be used later, in this case I will use the name 'overflow-content') in the styleClass attribute from <p:datatable>;
Include the following CSS rule in your page:
-
.overflow-content .ui-datatable-tablewrapper table {
overflow: auto;
width: 2500px;
}
The result will be something like this:
For this you need to first add the option scrollX: true and should add css to table width:100% inline.
$('#example').dataTable( {
"scrollX": true
} );
and you are done.

Resizing footer columns in ng-grid

I'm having a small issue with AngularJS and ng-grid.
I want to add a row in the footer that contains total values for each column. Using a footer template I managed to do that, so far so good.
Is there any way I can resize these columns based on the size of the grid's columns? Or at least set the row width to follow the width of the grid canvas?
Thanks in advance.
By using CoulmnDefs and using the same widths in your footer template.
$scope.gridOptions = {
data: 'myData',
enablePaging: true,
showFooter: true,
footerRowHeight:'30px',
footerTemplate: '<div style="width: 20%; display: inline-block;">{{total1}}</div><div style="width: 60%; display: inline-block;">{{total2}}</div><div style="display: inline-block;">{{total3}}</div>',
totalServerItems: 'totalServerItems',
columnDefs: [{
field: 'name',
width: '20%'
}, {
field: 'allowance',
width: '60%'
}, {
field: 'paid'
}],
pagingOptions: $scope.pagingOptions,
filterOptions: $scope.filterOptions
};
This is based on old Plunker I found somwhere.
If the grid gets to small this still goes bonkers. Try to set a minwidth for the grid in style.css or the for the columns in columnDefs and the footer template.

HTML5's 'data-' attribute overriding CSS 'content' property

I've looked far and wide and have been unable to find an explanation to this behavior.
Why does HTML5's data- attribute override my CSS content property on a common element?
So for example, I have the following element defined:
<th data-module-field="name" class="sortable sorted desc" data-bind="click:sort">Name</th>
And my CSS class is as follows:
.sortable.sorted.desc:after {
content: url(../Images/desc.gif);
margin-left: 3px;
}
With the data-module-field attribute set, the content image defined in the CSS class doesn't show up. However, if I remove the data- portion of this attribute (as follows), the content image displays correctly.
<th module-field="name" class="sortable sorted desc" data-bind="click:sort">Name</th>
Can anyone explain why this behavior occurs?

ExtJS: the magic of hidden columns

I wonder how ExtJS makes columns hidden without any visible CSS changes!
The problem that I had - I can't set the CSS rule to hide children icon in that hidden column. F.e. if the hidden td had class 'hidden', I can use something like that:
td.hidden img {display:none;}
But in this case I can do it only in renderer with manipulating grid.columns[col].isHidden().
renderer: function(value,td,record,row,col,store,view) {
return grid.columns[col].isHidden() ? '' : someFunctionToRenderColumn();
},
It's ok, but then if I show hidden column it will not refresh grid and shows empty column. Of course I can add one more event for show/hide that column, but it is so difficult! Has it any simple way?
It gives them a width of 0px:
<colgroup>
<col class="x-grid-cell-gridcolumn-1023" style="width: 0px;">
</colgroup>
... and that should hide your img too. Except if you've given them an absolute positionning or something. You should try to position your img using float, margin and padding. Or you will have to toggle the 'hidden' class yourself using the hide and show event of the column.
You can hide columns by targeting the corresponding col element. No need to put classes on each of the individual tds.
Here's a fiddle I made earlier: http://jsfiddle.net/MrLister/MupLH/
which has
<table>
<col><col class="invisible"><col>
...
and the CSS:
.invisible {visibility:collapse}
But you don't even need a class; you can also use col:nth-child(2) if you know the column number.

Resources