0

I have the following column configuration for my Angular Material mat-table columns:

export interface TableColumn {
  name: string;
  dataKey: string;
  isSortable?: boolean;
  width?: string; // column width
}

//...

this.tableColumns = [
    {
        name: 'Id',
        dataKey: 'id',
        position: 'left',
        width: '50px'
    },
    {
        name: 'Name',
        dataKey: 'name',
        position: 'left',
        width: '100%'
    }
];

As far as I see, many people use css in order to set column width as on this page, etc. However, would not it be nice if we set the column widths for each column by pixel and percentage in the this.tableColumns array as the other properties when defining columns? I think I just need a configuration of mat-table, but I am not sure if there is such a config for mat-table. If not, I think I can use [style.width] and set each column by column config value. Any suggestion for that?

Jack
  • 1
  • 21
  • 118
  • 236

2 Answers2

1

In general, you defined the columns based in your array like:

<ng-container *ngFor="let column of tableColumns;let first=first">
        <ng-container [matColumnDef]="column.dataKey">
            <th [style.width]="column.width" mat-header-cell *matHeaderCellDef>
                  {{column.name}}
            </th>
            <td [style.width]="column.width" mat-cell 
                 *matCellDef="let element"> {{element[column.dataKey]}}
            </td>
        </ng-container>
</ng-container>

And your displayedColumns as

this.displayedColumns=this.tableColumns.map(x=>x.dataKey)

NOTE: I supose you defined the width as '50%' or '30px' if only use a number you can use, e.g.

[style.width]="column.width+'px'"

Update imagine you want to create a column with actions buttons, but this buttons can be one, two or three. We can asign to this last colum a width of "1%" and 'white-space: nowrap'

//we has two variables
btDelete:boolean=true;
btEdit:boolean:true;

<ng-container matColumnDef="action">
    <th style="width:1%" mat-header-cell *matHeaderCellDef>
    </th>
    <td style="width:1%;white-space: nowrap;" mat-cell 
         *matCellDef="let element">
        <button *ngIf="btEdit" mat-button (click)="edit(element)">Edit</button>
        <button *ngIf="btDelete" mat-button (click)="delete(element)">Delete</button> 
    </td>
</ng-container>

NOTE: I'm not prety sure what happens with the width of columns because the % total is bigger that 100%

We can try using the mat-table in flex-mode

<ng-container *ngFor="let column of columns">
    <ng-container [matColumnDef]="column.name">
        <mat-header-cell [style.flex]="column.width" *matHeaderCellDef> {{column.width}}</mat-header-cell>
        <mat-cell [style.flex]="column.width" *matCellDef="let element"> {{element[column.name]}} </mat-cell>
    </ng-container>
</ng-container>
<ng-container matColumnDef="action">
    <mat-header-cell style="flex:0 1 auto;visibility:hidden" *matHeaderCellDef>
        <button *ngIf="btEdit" mat-button>Delete</button>
        <button *ngIf="btDelete" mat-button>Delete</button>
    </mat-header-cell>
    <mat-cell style="flex:0 1 auto" *matCellDef="let element"> <button *ngIf="btEdit" mat-button>Edit</button>
        <button *ngIf="btDelete" mat-button>Delete</button></mat-cell>
</ng-container>

See that the column "action" the "head" repeat the buttons -with visibility:hidden-

NOTE: In this case, the "with" -really the flex- is a number, not a %,

Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • That is exactly what I want and I think giving the width values as '50px' or '50%' will not be problem (the width will be set according to px or percentage values I think). Is that true? – Jack Oct 18 '20 at 13:39
  • On the other hand, I also need to set action column width that is a single column, not iterative. So, how can I set it in the `tableColumns` array? If I add a new value, it repeats, if I add as a new column, the added column will be tried to render as a new column. What is the best way for defining this in the `tableColumns` array? I know I can set it in the table, but as the table is **reusable** I want to set it in the config. Any idea? – Jack Oct 18 '20 at 13:39
  • Or should I create a new array like `actionColumn` for defining action column properties? – Jack Oct 18 '20 at 13:48
  • If you add a new column, you need change two things: the array tablecolumns and the variable displayedColumns. If you need an "action column" (and always is the same "action" -tipical one with a button edit-) just add a column manually -again, the displayedColumns must include this, so, if your action columns is called "action", you can do `this.displayedColumns=[...this.tableColumns.map(x=>x.dataKey),'action']` -using the spread operator to concat an array with another value -or use push after calculate the columns- – Eliseo Oct 18 '20 at 14:30
  • Thanks a lot for your help, voted up. Could you update your answer by adding this to complete the answer? On the other hand the action column will be always in the base table as the last column. But depending on the icon numbers (sometimes 2, sometimes 5) I need to set its width. So, setting it using a smart approach would be perfcet for me :) – Jack Oct 18 '20 at 15:15
  • @Jack, I updated the answer to add a "column action". I think that it's better aproach the las aproach using mat-table when "uses display flex", but, sincerly I'm has no so much experience using flex css. – Eliseo Oct 18 '20 at 19:58
  • Thanks a lot for all your helps and efforts. – Jack Oct 19 '20 at 09:13
  • Marked it as answer ;) – Jack Oct 19 '20 at 09:13
0

While there isn't a way to define column width in the array, you should be able to define it using ng-style. It is possible to provide column specific properties in the html template, therefore this too should work. An example would be

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
  <mat-text-column name="position" [headerText]="headerText" [ngStyle]="{'width':'20%'}"></mat-text-column>

  <!-- Change the header text. -->
  <mat-text-column name="name" headerText="Element" [ngStyle]="{'width':'40%'}"></mat-text-column>

  <!-- Provide a data accessor for getting the cell text values. -->
  <mat-text-column name="weight" [dataAccessor]="getWeight" [ngStyle]="{'width':'40%'}"></mat-text-column>
</table>

The result of style.width can also be accomplished by ngStyle, so that too should work in the same way.

Edric
  • 24,639
  • 13
  • 81
  • 91
Delwyn Pinto
  • 614
  • 1
  • 6
  • 14