Skip to main content

Overview

Conditional formatting combines three configuration elements:
  1. Cell Decorator — JavaScript function that evaluates cell data and applies CSS classes
  2. CSS Classes — Style definitions bound to those class names
  3. Cell Renderer Assignment — Links a column to its decorator function
This approach allows real-time visual feedback as users edit cells, making it easy to spot high-risk items, overdue tasks, or items requiring action.

Architecture Diagram

diagram

Configuration Structure

Cell Decorators Definition

PropertyTypeRequiredDescription
namestringYesUnique identifier for the decorator function
functionstringYesJavaScript function body (receives info parameter)
conditionexpressionNoOptional condition to determine which decorator applies
Example Configuration:
{
  "cellDecorators": {
    "rpnHighlight": "function(info){\n var val = info.value;\n $(info.cell).toggleClass('rpn1', val > 0 && val <= 150);\n $(info.cell).toggleClass('rpn2', val > 150 && val <= 350);\n $(info.cell).toggleClass('rpn3', val > 350);\n}",
    "severityColor": "function(info){\n var sev = info.item['severity'];\n $(info.cell).toggleClass('sev-low', sev === 'Low');\n $(info.cell).toggleClass('sev-medium', sev === 'Medium');\n $(info.cell).toggleClass('sev-high', sev === 'High');\n}"
  }
}

Cell Decorator Functions

Every cell decorator receives an info object with the following properties:
PropertyTypeDescription
info.valueanyCurrent cell value
info.itemobjectComplete work item row data
info.cellDOM elementThe cell DOM element to style
info.rownumberRow index in the grid
info.colnumberColumn index in the grid

Common Decorator Patterns

Pattern 1: Numeric Range Classification
function(info){
  var val = info.value;
  $(info.cell).toggleClass('low', val > 0 && val <= 150);
  $(info.cell).toggleClass('medium', val > 150 && val <= 250);
  $(info.cell).toggleClass('high', val > 250);
}
Pattern 2: Enum Value Matching
function(info){
  var status = info.item['status'];
  $(info.cell).toggleClass('approved', status === 'Approved');
  $(info.cell).toggleClass('rejected', status === 'Rejected');
  $(info.cell).toggleClass('pending', status === 'Pending');
}
Pattern 3: Dependent Condition (Cross-Row)
function(info){
  var rpn = info.item['rpnNew'];
  var hasTask = info.item['mitigationTask'] !== null;
  $(info.cell).toggleClass('unmitigated-risk', rpn > 200 && !hasTask);
  $(info.cell).toggleClass('addressed-risk', hasTask);
}
Pattern 4: Date-Based Formatting
function(info){
  var dueDate = new Date(info.item['dueDate']);
  var today = new Date();
  $(info.cell).toggleClass('overdue', dueDate < today);
  $(info.cell).toggleClass('due-soon', (dueDate - today) / (1000 * 60 * 60 * 24) <= 7);
}

CSS Classes Definition

Every CSS class used by cell decorators must be defined in the styles object:
PropertyTypeDefaultDescription
.classNamestringCSS style declaration as JSON string
!importantflagRequired when multiple decorators might conflict on same cell
Example Styles:
{
  "styles": {
    ".low": "{background-color: #eaf5e9 !important; color: #1d5f20 !important;}",
    ".medium": "{background-color: #fff3d2 !important; color: #735602 !important;}",
    ".high": "{background-color: #f8eae7 !important; color: #ab1c00 !important;}",
    ".approved": "{background-color: #d4edda; border-left: 4px solid #28a745 !important;}",
    ".rejected": "{background-color: #f8d7da; border-left: 4px solid #dc3545 !important;}",
    ".overdue": "{background-color: #ffcccc; font-weight: 600 !important;}",
    ".boldCol": "{font-weight: 600;}"
  }
}

Assigning Decorators to Columns

Link a cell decorator to a column using the cellRenderer property:
{
  "columns": [
    {
      "id": "rpn",
      "header": "RPN",
      "binding": "rpn",
      "cellRenderer": "rpnHighlight"
    },
    {
      "id": "severity",
      "header": "Severity",
      "binding": "severity",
      "cellRenderer": "severityColor"
    }
  ]
}

Critical Implementation Details

When evaluating enum columns in decorators, compare against the enum ID, not the display value.Incorrect:
$(info.cell).toggleClass('active', info.item['status'] === 'Active');
Correct:
$(info.cell).toggleClass('active', info.item['status'] === 'active');
Use the Configuration Editor or KB articles to find the correct enum ID for your project.
Always add !important to CSS declarations when multiple decorators might apply to the same cell. Without it, CSS specificity conflicts can cause styling to fail silently.
".high": "{background-color: #f8eae7 !important; color: #ab1c00 !important;}"
Always check for null/undefined values before accessing nested properties:
function(info){
  var task = info.item['mitigationTask'];
  $(info.cell).toggleClass('has-task', task !== null && task !== undefined);
}

Cell Decorator Execution Timing

Decorators execute at these points:
  • Grid Initialization — Applied when RISKSHEET first loads
  • Data Refresh — Re-applied when cells are edited and grid refreshes
  • Row Addition — Applied when new rows are inserted
  • Data Changes — Applied when linked data or formulas update
Decorators do not execute continuously; they trigger on specific grid events. For real-time updates, structure your data so formulas recalculate on cell edit.

Multiple Decorators on One Column

A single column can use only one cellRenderer, but that renderer can apply multiple CSS classes to create complex styling:
function(info){
  var rpn = info.value;
  var hasTask = info.item['mitigationTask'] !== null;
  
  // Apply risk level class
  $(info.cell).toggleClass('rpn1', rpn <= 150);
  $(info.cell).toggleClass('rpn2', rpn > 150 && rpn <= 350);
  $(info.cell).toggleClass('rpn3', rpn > 350);
  
  // Apply status class (independent of risk level)
  $(info.cell).toggleClass('bold', rpn > 200);
  $(info.cell).toggleClass('with-mitigation', hasTask);
}
Define all classes in the styles object:
{
  "styles": {
    ".rpn1": "{background-color: #eaf5e9 !important;}",
    ".rpn2": "{background-color: #fff3d2 !important;}",
    ".rpn3": "{background-color: #f8eae7 !important;}",
    ".bold": "{font-weight: 600 !important;}",
    ".with-mitigation": "{border-right: 3px solid #28a745 !important;}"
  }
}

Troubleshooting

IssueCauseSolution
Styling not appearingCSS class not definedAdd class to styles object
Some cells styled, others notCondition logic errorCheck enum IDs vs values
Styling overwrites unexpectedlyMissing !important flagAdd !important to CSS declarations
Decorator function errorsAccessing undefined propertyAdd null checks: if (info.item['field'] !== null)
Performance slow with many cellsToo many DOM updatesOptimize condition logic; avoid complex calculations

See Also

KB ArticlesSupport TicketsSource Code
  • AppConfig.ts
  • risksheet.json
  • SheetConstants.ts
  • ApprovalBasedReview.java
  • CellEditorFormatter.ts