Tree Grid Conditional Cell Styling
The IgxTreeGrid component in Ignite UI for Angular provides two ways to conditional styling of cells based on custom rules.
- By setting the
IgxColumnComponentinputcellClassesto an object literal containing key-value pairs. The key is the name of the CSS class, while the value is either a callback function that returns a boolean, or boolean value. The result is a convenient material styling of the cell.
// component.ts file
public beatsPerMinuteClasses = {
downFont: this.downFontCondition,
upFont: this.upFontCondition
};
...
private downFontCondition = (rowData: any, columnKey: any): boolean => {
return rowData[columnKey] <= 95;
}
// component.scss file
.upFont {
color: red;
}
.downFont {
color: green;
}
Demo with 'cellClasses'
- By using the
IgxColumnComponentinputcellStyleswhich accepts an object literal where the keys are style properties and the values are expressions for evaluation.
public styles = {
"background": "linear-gradient(180deg, #dd4c4c 0%, firebrick 100%)",
"text-shadow": "1px 1px 2px rgba(25,25,25,.25)",
"animation": "0.25s ease-in-out forwards alternate popin"
};
The callback signature for both
cellStylesandcellClassesis now changed to:
(rowData: any, columnKey: string, cellValue: any, rowIndex: number) => boolean
Demo with 'cellStyles'
Overview
Using cellClasses
You can conditionally style the IgxTreeGrid cells by setting the IgxColumnComponent cellClasses input and define custom rules.
<!-- sample.component.html -->
<igx-column field="UnitPrice" header="Unit Price" [dataType]="'number'" [cellClasses] = "priceClasses">
<ng-template igxCell let-cell="cell" let-val>
<span *ngIf="cell.row.rowData.UnitPrice == 0">-</span>
<span *ngIf="cell.row.rowData.UnitPrice != 0">${{val}}</span>
</ng-template>
</igx-column>
The cellClasses input accepts an object literal, containing key-value pairs, where the key is the name of the CSS class, while the value is either a callback function that returns a boolean, or boolean value.
// sample.component.ts
private upPriceCondition = (rowData: any, columnKey: any): boolean => {
return rowData[columnKey] > 25;
}
private downPriceCondition = (rowData: any, columnKey: any): boolean => {
return rowData[columnKey] <= 25;
}
public priceClasses = {
downPrice: this.downPriceCondition,
upPrice: this.upPriceCondition
};
// sample.component.scss
::ng-deep {
.upPrice {
color: red;
}
.downPrice {
color: green;
}
}
Use ::ng-deep or ViewEncapsulation.None to force the custom styles down through the current component and its children.
Using cellStyles
Columns now expose the cellStyles property which allows conditional styling of the column cells. Similar to cellClasses it accepts an object literal where the keys are style properties and the values are expressions for evaluation. Also, you can apply regular styling with ease (without any conditions).
In the sample above we've created:
- Two different styles that will be applied based on the column index.
- You will also change the
text colorbased on even/odd rows.
The callback signature for both
cellStylesis:
(rowData: any, columnKey: string, cellValue: any, rowIndex: number) => boolean
Let's define our styles:
// component.ts
public oddColStyles = {
background: "linear-gradient(to right, #b993d6, #8ca6db)",
color: (rowData, coljey, cellValue, rowIndex) => rowIndex % 2 === 0 ? "white" : "gray",
animation: "0.75s popin"
};
public evenColStyles = {
background: "linear-gradient(to right, #8ca6db, #b993d6)",
color: (rowData, coljey, cellValue, rowIndex) => rowIndex % 2 === 0 ? "gray" : "white",
animation: "0.75s popin"
};
On ngOnInit we will add the cellStyles configuration for each column of the predefined columns collection, which is used to create the IgxTreeGrid columns dynamically.
// component.ts
public ngOnInit() {
this.data = athletesData;
this.columns = [
{ field: "Id" },
{ field: "Position" },
{ field: "Name" },
{ field: "AthleteNumber" },
{ field: "CountryName" }
];
this.applyCSS();
}
public applyCSS() {
this.columns.forEach((column, index) => {
column.cellStyles = (index % 2 === 0 ? this.evenColStyles : this.oddColStyles);
});
}
public updateCSS(css: string) {
this.oddColStyles = {...this.oddColStyles, ...JSON.parse(css)};
this.evenColStyles = {...this.evenColStyles, ...JSON.parse(css)};
this.applyCSS();
}
// component.html
<igx-grid
#grid1 [data]="data"
primaryKey="ID"
width="80%"
height="300px">
<igx-column *ngFor="let c of columns"
[field]="c.field"
[header]="c.field"
[cellStyles]="c.cellStyles">
</igx-column>
</igx-grid>
Define a popin animation
// component.scss
@keyframes popin {
0% {
opacity: 0.1;
transform: scale(.75, .75);
filter: blur(3px) invert(1);
}
50% {
opacity: .5;
filter: blur(1px);
}
100% {
transform: scale(1, 1);
opacity: 1;
filter: none;
}
}
Known issues and limitations
- If there are cells bind to the same condition (from different columns) and one cell is updated, the other cells won't be updated based on the new value, if the condition is met.
A pipe check should be performed in order to apply the changes to the rest of the cells. The example below shows how to do that with a
spread operator... ononCellEditevent. This will copy the original object with a new instance, and lead pure pipe to be fired.
public backgroundClasses = {
myBackground: (rowData: any, columnKey: string) => {
return rowData.Col2 < 10;
}
};
...
editDone(evt) {
this.backgroundClasses = {...this.backgroundClasses};
}
<igx-grid #grid1 [data]="data" height="500px" width="100%" (onCellEdit)="editDone($event)">
<igx-column field="Col1" dataType="number" [cellClasses]="backgroundClasses"></igx-column>
<igx-column field="Col2" dataType="number" [editable]="true" [cellClasses]="backgroundClasses"></igx-column>
<igx-column field="Col3" header="Col3" dataType="string" [cellClasses]="backgroundClasses"></igx-column>
...