I want to create layaut similar to this one with Angular Material
I don't know how to add additional header row (blue one) before each group of rows.
This is what I have so far.
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container matColumnDef="env">
<th mat-header-cell *matHeaderCellDef> Env </th>
<td mat-cell *matCellDef="let element"> {{element.options.env}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
My data has layout:
{ [{options: {env: abc}, sublist: {[host1, host2, hostn]}}, ..]}
That's the way to do this (really need 4 more characters to post this?) https://stackblitz.com/edit/angular-mattable-with-groupheader?file=package.json
Related
I have an angular material table
(HTML)
<table mat-table
[dataSource]="dataSource" multiTemplateDataRows
class="mat-elevation-z8">
<ng-container *ngIf="{{column}}" matColumnDef="{{column}}" *ngFor="let column of displayedColumns">
<th mat-header-cell *matHeaderCellDef> {{column}} </th>
<td mat-cell *matCellDef="let element"> {{element[column]}} </td>
</ng-container>
I want to change the styling on the element if it equals 'Missing' (e.g. {{element[column}} == Missing then change styling).
(style) (HTML)
<mat-chip *ngIf="element.status=='Missing'" style="background-color: #ec9d9d; color: red">Missing</mat-chip>
How can I do this in the HTML? I only want to do this if the displayedColumn 'status' is equal to 'Missing'.
(Typescript)
displayedColumns: string[] = [
'id',
'tradingPartnerTradingPartner',
'fileFormatFileFormat',
'status',
];
you could use the ng-class directive
in your example, using it should be something like this:
(Assuming the mat-chip would get placed into this cell I modified below)
<table mat-table [dataSource]="dataSource" multiTemplateDataRows
class="mat-elevation-z8">
<ng-container *ngIf="{{column}}" matColumnDef="{{column}}" *ngFor="let column of displayedColumns">
<th mat-header-cell *matHeaderCellDef> {{column}} </th>
<td mat-cell *matCellDef="let element"
[ngClass]="{missing: element.status=='Missing' }"> {{element[column]}} </td>
</ng-container>
...
and don't forget to create the css for the .missing class we are referencing in the ngClass directive:
.missing {
background-color: #ec9d9d;
color: red
}
I have done a code to generate a datatable based on dynamic rows and columns. I need to add a html button in the last column of each row for edit. How to do that. Below is the code
<div class="example-table-container" >
<table mat-table [dataSource]="data" class="example-table"
matSort matSortActive="created" matSortDisableClear matSortDirection="desc">
<ng-container *ngFor="let disCol of this.columnHeading | keyvalue; let colIndex = index" matColumnDef="{{disCol.key}}">
<th mat-header-cell *matHeaderCellDef><b>{{disCol.value}}</b></th>
<td mat-cell *matCellDef="let element">{{element[disCol.key]}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
When i insert html code in value the button is not appearing but only html code is appearing like this
<button>Edit</button>
I have tried the bypassSecurityTrustHtml also. It gives the error safeValue must use [property]=binding:
Angular material table provides a stickyend property with some css.
Normally we add an extra th with stickyend to solve that.
Below is an example of that..
<ng-container matColumnDef="star" stickyEnd>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let element">
<mat-icon>more_vert</mat-icon>
</td>
</ng-container>
https://stackblitz.com/angular/nneoarrlekb?file=src%2Fapp%2Ftable-sticky-columns-example.html
<table mat-table [dataSource]="data" class="example-table"
matSort matSortActive="created" matSortDisableClear matSortDirection="desc">
<ng-container *ngFor="let disCol of this.columnHeading | keyvalue; let colIndex = index" matColumnDef="{{disCol.key}}">
<th mat-header-cell *matHeaderCellDef ><b >{{disCol.value}}</b></th>
<td mat-cell *matCellDef="let element" [innerHtml]="element[disCol.key]"></td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;">
</tr>
</table>
I have done this using the innerhtml
try to add this
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef></mat-header-cell>
<mat-cell *matCellDef="let row">
<button mat-icon-button (click)="onEdit(row)"><mat-icon>launch</mat-icon></button>
<button mat-icon-button color="warn" (click)="onDelete(row.$key)"><mat-icon>delete_outline</mat-icon></button>
</mat-cell>
</ng-container>
do not forget to add this column in displayedColumns
displayedColumns: string[] = ['fullName', 'email', 'mobile', 'city', 'departmentName', 'actions'];
I was in a similar predicament to you and this is what I came up with.
Firstly, trying to add the html button tag as a value is not a solution and akin to html injection.
Given an example set of columns,
const columnHeadings = ['position', 'firstName', 'lastName', 'actions'];
const displayNames = ['No.', 'First Name', 'Last Name', 'Actions'];
we may dynamically populate our table. What I have done here is presented different content for my one column, 'actions', based on a condition that is triggered by the desired column.
<table mat-table [dataSource]="data" class="example-table">
<ng-container matColumnDef="{{disCol}}" *ngFor="let disCol of columnHeadings; index as i">
<th mat-header-cell *matHeaderCellDef> {{displayNames[i]}} </th>
<td mat-cell *matCellDef="let element">
<div *ngIf="column!=='actions'"> {{element[disCol]}} </div>
<div *ngIf="column==='actions'">
<button mat-icon-button>
<mat-icon>edit</mat-icon>
</button>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnHeadings"></tr>
<tr mat-row *matRowDef="let element; columns: columnHeadings;" class="element-row"></tr>
</table>
By no means have a done a very elegant way to execute this but it is one that works; even if it is somewhat of a "hack" solution.
I'm pretty new to Angular and I'm trying to create a table to better display my data. I'm getting the data from a JSON provided by my server.
Content of data.component.html:
<div class="container">
<h1>Search history</h1>
<table *ngIf="searches">
<li *ngFor="let search of searches">
<p class="searchParams">{{search.searchParams}}</p>
<p class="searchDate">{{search.searchDate | date: "yyyy-MM-dd hh:mm"}}</p>
</li>
</table>
</div>
Content of data.component.ts:
#Component({
selector: 'app-data',
templateUrl: './data.component.html',
styleUrls: ['./data.component.scss']
})
export class DataComponent implements OnInit {
searches: Object;
constructor(private _http: HttpService) {
}
ngOnInit() {
this._http.getSearches().subscribe(data => {
this.searches = data;
console.log(this.searches);
});
}
}
What I get is something that looks like a bullet list:
I'm trying to take this as example but I don't understand how to implement it. What is my datasource here? What HTML should I write to get such a nice looking table?
If you want something like the angular material table you should actually use it and follow the docs.
If you don't want to use angular material but instead just want a regular HTML table you should adjust you code like that to use actuale table rows and colums:
<div class="container">
<h1>Search history</h1>
<table *ngIf="searches">
<tr *ngFor="let search of searches">
<td class="searchParams">{{search.searchParams}}</p>
<td class="searchDate">{{search.searchDate | date: "yyyy-MM-dd hh:mm"}}</p>
</tr>
</table>
</div>
You can then style your table via CSS.
For an angular material approach you should first install the package and import it to your module. Then you could use a template like that:
<table mat-table [dataSource]="searches" class="mat-elevation-z8">
<!-- searchParams Column -->
<ng-container matColumnDef="searchParams">
<th mat-header-cell *matHeaderCellDef> Search parameters </th>
<td mat-cell *matCellDef="let element"> {{element.searchParams}} </td>
</ng-container>
<!-- searchDate Column -->
<ng-container matColumnDef="searchDate">
<th mat-header-cell *matHeaderCellDef> Date </th>
<td mat-cell *matCellDef="let element"> {{element.searchDate}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
dont forget to define displayColumns in code behind:
displayedColumns: string[] = ['searchParams', 'searchDate'];
Something like this could work,
data.component.html
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!-- Position Column -->
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef> No. </th>
<td mat-cell *matCellDef="let element"> {{element.position}} </td>
</ng-container>
<!-- Keyword Column -->
<ng-container matColumnDef="keyword">
<th mat-header-cell *matHeaderCellDef> Keyword </th>
<td mat-cell *matCellDef="let element"> {{element.keyword}} </td>
</ng-container>
<!-- Limit Column -->
<ng-container matColumnDef="limit">
<th mat-header-cell *matHeaderCellDef> Limit </th>
<td mat-cell *matCellDef="let element"> {{element.limit}} </td>
</ng-container>
<!-- Date Search Column -->
<ng-container matColumnDef="dateSearch">
<th mat-header-cell *matHeaderCellDef> Date Search </th>
<td mat-cell *matCellDef="let element"> {{element.dateSearch | date: "yyyy-MM-dd hh:mm"}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</tabl1e>
data.component.ts
#Component({
selector: 'app-data',
templateUrl: './data.component.html',
styleUrls: ['./data.component.scss']
})
export class DataComponent implements OnInit {
searches: Object;
displayedColumns: string[] = ['position', 'keyword', 'limit', 'date'];
dataSource = ELEMENT_DATA;
constructor(private _http: HttpService) {
}
ngOnInit() {
this._http.getSearches().subscribe(data => {
this.searches = data;
this.dataSource = data.map((v, i) => {
position: i,
keyword: v.searchParams.keyword,
limit: v.searchParams.limit,
dateSearch: v.searchDate
});
console.log(this.searches);
});
}
}
I have a table with rows and when a certain condition is met (for each row) the background color is light red.
For every row, on hover, I change the background to light gray.
Problem is, I want the special rows (those that get the light red color already) to be colored with a deeper shade of red on hover (And not gray like all the other rows).
Best result I could get is having the red rows color a single column on hover with deep red but the rest of the row is still painted gray.
.css (without the single column coloring bug):
.cheaterRow {
background-color: rgb(255, 130, 130);
}
.mat-row:hover{
background-color:rgb(201, 201, 201);
}
.html:
<table
mat-table
[dataSource]="dataSource"
matSort
matSortActive="score"
matSortDirection="desc"
*ngIf="!loadingData; else loading"
class="row"
>
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header
class="sortHeader">
No.
</th>
<td mat-cell *matCellDef="let element">{{ element.id }}</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th>
<td mat-cell *matCellDef="let element">{{ element.name | titlecase }}</td>
</ng-container>
<ng-container matColumnDef="level">
<th mat-header-cell *matHeaderCellDef>
<mat-form-field>
<mat-label>Level</mat-label>
<mat-select (selectionChange)="onChangeLevel($event.value)">
<mat-option>None</mat-option>
<mat-option *ngFor="let level of levels" [value]="level.value">
{{ level.value | titlecase }}
</mat-option>
</mat-select>
</mat-form-field>
</th>
<td mat-cell *matCellDef="let element">
{{ element.level | titlecase }}
</td>
</ng-container>
<ng-container matColumnDef="score">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Score</th>
<td mat-cell *matCellDef="let element">{{ element.score }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr
mat-row
*matRowDef="let row; let even = even; columns: displayedColumns"
[class.cheaterRow]="isCheater(row.id)"
></tr>
</table>
I want the entire row to be colored differently (depending on the condition) on hover.
make your last tr in your table with your customized condtions by writing classes in your css (my css classes are positive ,negative ,cancelled ,highlight)
<tr
[ngClass]="{'positive' :(row.status?row.status===1:false) ,
'negative' :(row.status?row.status===2:false) ,
'cancelled':(row.status?row.status===4:false),
'highlight': selectedRowIndex == row}"
mat-row *matRowDef="let row; columns: displayedColumns;">
</tr>
You could add a data attribute and apply custom css
<tr
mat-row
*matRowDef="let row; let even = even; columns: displayedColumns"
class="row"
[attr.data-isCheater]="isCheater(row.id)"
></tr>
css
.row{
background:gray
}
.row[data-isCheater='true']:hover{
background: red
}
If you have additional conditions and some rows which match multiple then you can simply organise your css so that conditions you want to take priority lower in the .css stylesheet
I am trying to make reusable material table and I want to use TemplateRef with ngTemplateOutlet to generate columns. In this example I created cards components which is using my material-table component. In cards.component.html I have template of one of my table's column. Running the project will cause an error ERROR TypeError: Cannot read property 'template' of undefined (see console on stackblitz). Is it possible to pass columnt template to my MaterialTableComponent and use it to define column?
<table mat-table [dataSource]="data" class="mat-elevation-z4">
<ng-container
*ngFor="let column of displayedColumnObjects"
[matColumnDef]="column.id"
>
<!-- if where is cellTemplate in table config json, use cellTemplate -->
<ng-container
*ngIf="column.cellTemplate"
[ngTemplateOutlet]="column.cellTemplate"
>
</ng-container>
<ng-container *ngIf="!column.cellTemplate">
<th mat-header-cell *matHeaderCellDef> {{column.title}} </th>
<td mat-cell *matCellDef="let element"> {{element[column.id]}} </td>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
</table>
UPDATE
I found solution using ngTemplateOutletContext.
<table mat-table [dataSource]="data" class="mat-elevation-z4">
<ng-container
*ngFor="let column of displayedColumnObjects"
[matColumnDef]="column.id"
>
<ng-container
*ngIf="column.cellTemplate"
>
<th mat-header-cell *matHeaderCellDef> {{column.title}} </th>
<td mat-cell *matCellDef="let element">
<ng-template
[ngTemplateOutletContext]="{
element: element[column.id]
}"
[ngTemplateOutlet]="column.cellTemplate">
</ng-template>
</td>
</ng-container>
<ng-container *ngIf="!column.cellTemplate">
<th mat-header-cell *matHeaderCellDef> {{column.title}} </th>
<td mat-cell *matCellDef="let element"> {{element[column.id]}} </td>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
</table>
See my example
ADD THE FOLLOWING IN THE COMPONENT TO BE RE-USED
In the '.HTML' file:
<ng-container [ngTemplateOutlet] = "yourNameReference"
[ngTemplateOutletContext] = "{$ implicit: {name: 'Arthur', lastName: 'Lemos'}">
</ng-container>
[NgTemplateOutletContext] data will be sent to the parent component. Remembering that '$ implicit' can receive any data you want to send to the PAI component
In the '.ts' file OF THE REUSABLE COMPONENT add the following code WITHIN YOUR CLASS
#ContentChild ('yourNameReference') yourNameReference: TemplateRef <any>;
FATHER COMPONENT (RECEIVES THE RE-USED COMPONENT)
Add the following code to the '.html' file
<ng-template #yourNameReference let-myDataa>
<p> {{myDataa.name}} {{myDataa.lastName}} </p>
</ng-template>
That way you can send data from the child component to the parent component, so you can create dynamic columns for your table.
Just follow the steps above, however, applying the specific columns of the table ... EX:
<td> <ng-container [ngTemplateOutlet] = "yourNameReference"
[ngTemplateOutletContext] = "{$ implicit: {name: 'Arthur', lastName: 'Lemos'}">
</ng-container> </td>
Add to the child's .ts:
#ContentChild ('yourNameReference') yourNameReference: TemplateRef <any>;
In the parent component:
<my-table>
...
<ng-template #yourNameReference let-myDataa>
<p> {{myDataa.name}} {{myDataa.lastName}} </p>
</ng-template>
<! - this content will be rendered inside the table ... ->
...
</my-table>
YOU CAN CREATE A REFERENCE NAME FOR EACH COLUMN, AND REPEAT THE PROCESS
ANGLE VERSION: 9
DOCUMENTATION: https://angular.io/api/common/NgTemplateOutlet
The documentation does not show the use of ngTemplateOutlet in different components, but it already helps in something.