MatPaginator unexpected behaviour inside ngIf? - css

STACKBLITZ DEMO
I have a material table as following:
<table mat-table [dataSource]="dataSource" >
... Rows ...
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator #MatPaginator [pageSizeOptions]="[4]" showFirstLastButtons></mat-paginator>
I need the table to be hidden when the variable info is false.
Attempt 1:
<table *ngIf="info" mat-table [dataSource]="dataSource" >
It works fine but the pagination does not work when info is true and all rows are displayed on the first page.
Attempt 2:
<table [hidden]="!info" mat-table [dataSource]="dataSource" >
Makes the pagination work, but when info is false the table is still displayed with no results.
Attempt 3:
Tried to sourround the whole table with a div and apply *ngIf to the div. Result: Same problem as in first attempt.
Tried to apply [hidden] to the div but still not hidding.
EDIT: Attempt 4:
Applied directly to the envolving div css style="display:none" and getting the same result as in attempt 3, the table is shown even if it has no values.
Any idea on how to hide the table when info is false and show it
when info is true with a working pagination?
Thanks!

Use this way
[hidden]="true"
<div [hidden]="true" >
<table mat-table [dataSource]="dataSource" >
<ng-container matColumnDef="test">
<th mat-header-cell *matHeaderCellDef> Test. </th>
<td mat-cell *matCellDef="let exp"> {{exp}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator #MatPaginator [pageSizeOptions]="[2, 4, 6]" showFirstLastButtons>
</mat-paginator>
<div>
stackblitz demo
make sure to change your condition in [hidden]

you can use ngClass to add dynamic class and use that class to hide the table like
[ngClass]="{'hidden': !info}"
and in your style.css
.hidden{
display:none;
}
demo

You can't put the paginator inside a ngIf, otherwise, when you set this.dataSource.paginator = this.paginator, this.paginator is undefined. There is a solution if you REALLY want to ngIf it (tell me if it is realy necessary), but I recommend changing it to hidden instead.

Angular 8 solution:
[hidden] can be used instead of *ngIf and activation of the tab can be done using CSS properties.
.tableClass .mat-tab-group.mat-primary .mat-ink-bar {
width: 160px !important;
}
<div [hidden]="true" class="tableClass">
<mat-tab-group>
<mat-tab label="Tab1">
</mat-tab>
<mat-tab label="Tab2">
</mat-tab>
</mat-tab-group>
</div>

I had the same problem because I was using the *ngIf and async pipe in my template and pagination was not working. After some research I was able to make it work using the #ViewChild annotation and a set function so I decided to share my complete solution here :)
The hidden solution propose by other answers didn't work for me.
In my component.ts file:
constructor(private cdRef: ChangeDetectorRef) { }
private paginator: MatPaginator;
/*
We are using #ViewChild because of the ngIf with async pipe on the template
When the data is emmited for the first time from the observable, we need to bind the
pagination component with the datasource. This can be achieved with the code bellow.
*/
#ViewChild(MatPaginator) set matPaginator(mp: MatPaginator) {
if(mp) {
this.paginator = mp;
this.dataSource = new MatTableDataSource<any>(your_data);
this.dataSource.paginator = this.paginator;
this.cdRef.detectChanges();
}
}
and in my template file:
// my observable with the async pipe
<div *ngIf="raceList$ | async as races">
<div class="mat-table-width">
<table mat-table [dataSource]="dataSource">
...
</table>
<mat-paginator [pageSizeOptions]="[10, 20, 30]"
showFirstLastButtons
aria-label="select page of races">
</mat-paginator>
</div>
</div>
With this solution I was able to display the data in the table and make pagination work.

Related

Weird behavior of css class in td with rowspan (Angular)

I'm using a custom css class called 'td-group' to customize td with a rowspan, to be more specific [attr.rowspan] since i'm using angular. In short words, the css style doesn't always get applied correctly, i've looked everywhere and tried everything and still didn't figure it out
The bug only occurs on chrome and never in edge
Here the image of the bug
<tr *ngFor="let r of list; let i = index">
<ng-container *ngIf="group && r.representative.show">
<td class="td-group" [attr.rowspan]="r.representative.height">
{{r.representative.name}}
</td>
</ng-container>
<td *ngFor="let c of cols">
{{r[c.name]}}
</td>
</tr>
Stackblitz https://stackblitz.com/edit/angular-yr3pxq?file=src/app/app.component.html

Angular: add class to span selector

I have the below code, I want to add a class to a span selector, but I have this error
Cannot read property 'classList' of null
<th *ngFor="let column of columns;"
<ng-container *ngIf="column?.sortable">
<span [id]="'sort-'+column?.field" (click)="sortArray(column?.field)"></span>
</ng-container>
</th>
if (this.columns) {
this.columns.forEach(column => {
if (column.sortable) {
const parent: HTMLElement = document.getElementById("sort-" + column.field);
this.renderer.setElementClass(parent, "sorting_asc", true);
}
})
}
I think you have overly complicated your code, You are using angular and I believe its not a good practice to access DOM elements using document.getElementById().
For your code to work, you will need to ensure that the view has loaded before you can access the DOM elements. You need to move your code to the AfterViewInit life cycle hook.
Below is how I would refactor the code
<th *ngFor="let column of columns;"
<ng-container *ngIf="column?.sortable">
<span [class.sorting_asc]="column?.sortable" (click)="sortArray(column?.field)"></span>
</ng-container>
</th>
We simply bind to [class.sorting_asc]="column?.sortable" and let angular apply the classes for us

using NG-CLASS inside of a mat table referring to a "row" element for css decleration

I have a mat table with several columns. One of the columns is a status field. I want to put colored badges in that column for the status that record has. I made them non clickable buttons. A record can have one of the 3 statuses "Completed", "Deleted", and "Canceled". I cannot seem to get it to work dynamically when it loads to set the colors. I have seen many examples where people use ng-class and I am trying hard to implement it, or more so to refer to the value of row.OrderStatus.
HTML
<!-- Status Column -->
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef>Status</th>
<td mat-cell *matCellDef="let row">
<button ng-class="row.OrderStatus">{{row.OrderStatus}}</button>
</td>
</ng-container>
CSS
.Completed{
background: green;
}
.Cancelled{
background: yellow;
}
.Deleted{
background: red;
}
That is the incorrect syntax for ngClass. Check out the docs for the correct syntax.
This should work for you.
<button [ngClass]="{'Completed': row.OrderStatus === 'Completed', 'Deleted': row.OrderStatus === 'Deleted', 'Cancelled': row.OrderStatus === 'Cancelled'}">
{{row.OrderStatus}}
</button>

semantic ui - how to style table headings

So I have built a table in semantic-ui. very simple. however styles dont seem to apply to my table in certain aspects and i cant get the headings to map over the columns. see the below screenshot
the L column is fine but the others are a bit wonky and name is just well off. how can i adjust the styles so make this work?
I have tried to add a width to the div my table sits in but it just extends it without altering the table body or head
here is the code:
<div className="tableContainer">
<h1> Table </h1>
<table className="ui striped table">
<thead>
<tr>
<th className="headings">Ranks</th>
<th className="headings">Name</th>
<th className="headings">P</th>
<th className="headings">W</th>
<th className="headings">L</th>
</tr>
</thead>
<tbody>
{this.props.players.sort(function(a, b) {
return (a.rank) - (b.rank);
}).map(function(player, index) {
index +=1;
return <tr key={index} className="table-rows">
<td className="stats">{player.rank}</td>
<td className="stats">{player.name}</td>
<td className="stats">{player.played}</td>
<td className="stats">{player.wins}</td>
<td className="stats">{player.losses}</td>
</tr>
}, this)}
</tbody>
</table>
</div>
If you are working in Reactjs, you should use Semantic-UI's reactjs package: Semantic-UI React. In the Table section, you can see that certain properties are passed through props. You can set the column number with columns prop. And under the Table.Header tab, you can see that there's a className prop. You can use it to style your header. For reference, visit: Semantic-UI React Table.

How to highlight a selected row in *ngFor?

I couldn't find something that will help me to solve this issue in Angular2. I'd like to set a css class when I select a row. (without using jQuery)
<table class="table table-bordered table-condensed table-hover">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Website</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of companies" (click)="selectedCompany(item, $event)">
<td>{{item.name}}</td>
<td>{{item.email}}</td>
<td>{{item.website}}</td>
</tr>
</tbody>
</table>
I'm using Angular2 final release
There are plenty of solutions to do this, one of them is you can store the current company when clicked.
In the *ngFor you check if the current item is the currentCompany and you add the class highlighted or whatever class you wish if its the same company.
export class TableComponent {
public currentCompany;
public selectCompany(event: any, item: any) {
this.currentCompany = item.name;
}
}
And then on your template:
<tr *ngFor="let item of companies" (click)="selectCompany($event, item)"
[class.highlighted]="item.name === currentCompany">
--
Another solution if you wish to have multiple highlighted companies you can add a property highlighted to your item. Then on selectCompany() you just set the property to true. On your check you do [class.highlighted]="item.highlighted".
I know this was answered a while ago, but to expand on the accepted answer, you could also use [ngClass]="{'class_name': item.id === currentCompany }". The table hover may need to be removed as it may hide the background color change
<tr *ngFor="let item of companies" (click)="selectCompany($event, item)" [ngClass]="{'class_name': item.id === currentCompany }" >
Then css
.class_name{ background-color: yellow; }

Resources