# Conditional Row Style

**URL:** <https://forum.inductiveautomation.com/t/conditional-row-style/107909>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [June 28, 2025, 3:48pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909 "2025-06-28T15:48:46Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![Steven\_Ham1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven_ham1/32/64482_2.png) [@Steven\_Ham1](https://forum.inductiveautomation.com/u/Steven_Ham1)\
**Post date:** [June 28, 2025, 3:48pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/1 "2025-06-28T15:48:46Z")

</div>

I need some help. I have a perspective table that I want a specific row to flash when the Status column is "Active". For some reason, my transform code is not working. Could someone review it and see what I may be missing? I do know that my "flashingRow" style class works; I have put it into the row's style in the property editor, and I can get all the rows to flash. However, when I try to make it conditional, it doesn't work. I do have rows striped enabled. But I have tried with that disabled as well. Any help would be greatly appreciated.

```python
def transform(self, value, quality, timestamp):
	headers = system.dataset.getColumnHeaders(value)
	styled_data = []
	
	for rowIndex in range(value.getRowCount()):
	    row_data = {}
	    for colIndex in range(value.getColumnCount()):
	        col_name = headers[colIndex]
	        row_data[col_name] = value.getValueAt(rowIndex, colIndex)
	
	    # Add the row-level 'style' key
	    if row_data.get("Status") == "Active":
	        row_data["style"] = {"classes": "flashingRow"} 
	    else:
	        row_data["style"] = {}
	
	    styled_data.append(row_data)
	
	return styled_data

```

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [June 28, 2025, 4:00pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/2 "2025-06-28T16:00:53Z")

</div>

> [@Steven\_Ham1](#):
>
> `row_data["style"] = {"classes": "flashingRow"}`

Post a few lines of the data array so we can see what _is_ returned. Maybe add a non-existent class to the `else` code so we'll get something. e.g.,  
`row_data["style"] = {"classes": "nonFlashingRow"}`

* * *

According to [[Feedback] NEW Perspective Table - #30 by ynejati](https://forum.inductiveautomation.com/t/feedback-new-perspective-table/21199/30) you seem to be styling it correctly.

> Rows can now be configured with their own styles.

```python
    { 
        "value": { // The rows value. 
            "city": "Folsom" 
            "country": "United States", 
            "population": 1000000 
        }, 
        "style": { // Custom row styles.
            "backgroundColor": "#F7901D",
            "classes": "some-class"
        }
    } 

```

---

<div class="post-metadata">

**Author:** ![Steven\_Ham1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven_ham1/32/64482_2.png) [@Steven\_Ham1](https://forum.inductiveautomation.com/u/Steven_Ham1)\
**Post date:** [June 28, 2025, 5:02pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/3 "2025-06-28T17:02:34Z")

</div>

Thank you for your help. Here is the print log of the file:

```python
INFO | jvm 1 | 2025/06/28 11:52:20 | I [StyledDataLogger] [11:52:20.469]: Row 0: {u'Status': u'Active', u'Duration': 4.25, u'EndOfDownTime': None, u'StartOfDownTime': 2025-06-28 07:37:22.493, 'style': {'classes': 'flashingRow'}} view=Page/PressPage@C, component=root/DownTime Table, project-name=CDC_MES_1, target=props.data
INFO | jvm 1 | 2025/06/28 11:52:20 | I [StyledDataLogger] [11:52:20.472]: Row 1: {u'Status': u'Complete', u'Duration': 5.98, u'EndOfDownTime': 2025-06-28 06:00:00.023, u'StartOfDownTime': 2025-06-28 00:01:00.017, 'style': {}} view=Page/PressPage@C, component=root/DownTime Table, project-name=CDC_MES_1, target=props.data

```

Then I added the nonexistent class:

```python
INFO | jvm 1 | 2025/06/28 12:00:24 | I [StyledDataLogger] [12:00:24.715]: Row 0: {u'Status': u'Active', u'Duration': 4.38, u'EndOfDownTime': None, u'StartOfDownTime': 2025-06-28 07:37:22.493, 'style': {'classes': 'flashingRow'}} view=Page/PressPage@C, component=root/DownTime Table, project-name=CDC_MES_1, target=props.data
INFO | jvm 1 | 2025/06/28 12:00:24 | I [StyledDataLogger] [12:00:24.715]: Row 1: {u'Status': u'Complete', u'Duration': 5.98, u'EndOfDownTime': 2025-06-28 06:00:00.023, u'StartOfDownTime': 2025-06-28 00:01:00.017, 'style': {'classes': 'nonFlashingRow'}} view=Page/PressPage@C, component=root/DownTime Table, project-name=CDC_MES_1, target=props.data

```

I would thought I would have seen some type of error.

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [June 28, 2025, 5:25pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/4 "2025-06-28T17:25:12Z")

</div>

Extracting the data from your logger, it looks OK.

```python
Row 0: {
    u'Status': u'Active', 
    u'Duration': 4.25, 
    u'EndOfDownTime': None, 
    u'StartOfDownTime': 2025-06-28 07:37:22.493, 
    'style': {'classes': 'flashingRow'}
} 
Row 1: {
    u'Status': u'Complete', 
    u'Duration': 5.98, 
    u'EndOfDownTime': 2025-06-28 06:00:00.023, 
    u'StartOfDownTime': 2025-06-28 00:01:00.017, 
    'style': {}
} 

```

1. When you expand the `data` property and look at `data[0]` and `data[1]` what do you see?
2. Where is your code being applied? Normally we would do a query binding (or similar) on `props.data` to get the raw data and then run your script in a Script Transform on the original binding. Is that what you are doing?

I would have thought you could simplify your code to something like,

```python
for row in value:
	if row("Status") == "Active":
		style = {"classes": "flashingRow"} 
	else:
		style = {}
	styled_data.append({"value": row, "style": style)

	return styled_data

```

but I could be wrong.

---

<div class="post-metadata">

**Author:** ![Steven\_Ham1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven_ham1/32/64482_2.png) [@Steven\_Ham1](https://forum.inductiveautomation.com/u/Steven_Ham1)\
**Post date:** [June 28, 2025, 5:56pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/5 "2025-06-28T17:56:04Z")

</div>

I can not look at the data coming in on data 0 or data 1 since the table is only part of a view. My data is coming in a dataset, could that be a problem? I did try it using a JSON, but it didn't work that way either, but I may have missed something.

Yes, I am using the binding on the table.prop.data using a query to pull the data, then the code I presented is a transform script. I didn't think this would be such a challenge. 🙂

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [June 29, 2025, 12:22am UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/6 "2025-06-29T00:22:45Z")

</div>

> [@Steven\_Ham1](#):
>
> My data is coming in a dataset, could that be a problem

I'm almost 100% certain that this is the issue. Datasets don't care for the dict you're providing for the style; it doesn't get set properly. You'll need to convert the dataset to a list of dicts instead

---

<div class="post-metadata">

**Author:** ![Steven\_Ham1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven_ham1/32/64482_2.png) [@Steven\_Ham1](https://forum.inductiveautomation.com/u/Steven_Ham1)\
**Post date:** [June 29, 2025, 1:36pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/7 "2025-06-29T13:36:53Z")

</div>

Thank you for your help. This morning, I changed the dataset to JSON and redid the code. Still not flashing.

```python
	
	styled_data = []
	
	for row in value:
	    
	    if row.get("Status") == "Active":
	        row["style"] = {"classes": "flashingRow"}
	    else:
	        row["style"] = {}
	
	    
	    system.util.getLogger("StyledDataLogger").infof("Row: %s", row)
	
	    styled_data.append(row)
	
	return styled_data

```

```python
INFO | jvm 1 | 2025/06/29 08:26:47 | I [StyledDataLogger] [08:26:47.424]: Row: {"StartOfDownTime":1751203140580,"EndOfDownTime":null,"Duration":0.12,"Status":"Active","style":{"classes":"flashingRow"}} view=Page/PressPage@C, project-name=CDC_MES_1, component=root/DownTime Table, target=props.data

```

So everyone can see the upstream process, here is the query that I use to pull the data from the table,

```python
SELECT 
    PressDownTime.StartOfDownTime,
    PressDownTime.EndOfDownTime,
    CAST(SUM(DATEDIFF(MINUTE, PressDownTime.StartOfDownTime, 
        ISNULL(PressDownTime.EndOfDownTime, GETDATE()))
    ) / 60.0 AS DECIMAL(10,2)) AS Duration,
    CASE 
        WHEN PressDownTime.EndOfDownTime IS NULL THEN 'Active'
        ELSE 'Complete'
    END AS Status
FROM 
    PressDownTime
WHERE 
    PressDownTime.PressID = :PressIDPass
    AND PressDownTime.StartOfDownTime >= :PressDateRangePastPass
    AND ISNULL(PressDownTime.EndOfDownTime, GETDATE()) <= :PressDateRangeFuturePass
GROUP BY 
    PressDownTime.PressID, 
    PressDownTime.StartOfDownTime, 
    PressDownTime.EndOfDownTime;

```

Any help will be greatly appreciated.

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [June 29, 2025, 3:14pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/8 "2025-06-29T15:14:19Z")

</div>

Right-click on the table's props.data, copy and paste it here as code. We only need a few array entries, so you can truncate it (keeping the closing brackets so that it's valid JSON) to keep the post short.

---

<div class="post-metadata">

**Author:** ![Steven\_Ham1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven_ham1/32/64482_2.png) [@Steven\_Ham1](https://forum.inductiveautomation.com/u/Steven_Ham1)\
**Post date:** [June 29, 2025, 3:40pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/9 "2025-06-29T15:40:14Z")

</div>

I'm not sure if this is what you intended for me to do. This is the code from the binding. Is this what you are asking me to post?

```python
{
  "type": "query",
  "config": {
    "polling": {
      "enabled": true,
      "rate": "120"
    },
    "designerUseLimit": false,
    "queryPath": "MachineHours/PressDownTimeByDateTable",
    "parameters": {
      "PressDateRangePastPass": "{../From Date.props.value}",
      "PressDateRangeFuturePass": "{../To Date.props.value}",
      "PressIDPass": "{session.custom.MachineID}"
    }
  },
  "transforms": [
    {
      "code": "\tlogger \u003d system.util.getLogger(\"StyledDataLogger\")\n\t\n\theaders \u003d system.dataset.getColumnHeaders(value)\n\tstyled_data \u003d []\n\t\n\tfor rowIndex in range(value.getRowCount()):\n\t row_data \u003d {}\n\t for colIndex in range(value.getColumnCount()):\n\t col_name \u003d headers[colIndex]\n\t row_data[col_name] \u003d value.getValueAt(rowIndex, colIndex)\n\t\n\t # Add the row-level \u0027style\u0027 key\n\t if row_data.get(\"Status\") \u003d\u003d \"Active\":\n\t row_data[\"style\"] \u003d {\"classes\": \"flashingRow\"}\n\t else:\n\t row_data[\"style\"] \u003d {\"classes\": \"nonFlashingRow\"}\n\t\n\t styled_data.append(row_data)\n\t logger.info(\"Row {}: {}\".format(rowIndex, row_data))\n\t\n\treturn styled_data",
      "type": "script"
    }
  ]
}

```

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [June 29, 2025, 4:22pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/10 "2025-06-29T16:22:09Z")

</div>

No, we want to see what was _returned_ by the binding, not the binding itself.

---

<div class="post-metadata">

**Author:** ![Steven\_Ham1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven_ham1/32/64482_2.png) [@Steven\_Ham1](https://forum.inductiveautomation.com/u/Steven_Ham1)\
**Post date:** [June 29, 2025, 4:37pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/11 "2025-06-29T16:37:35Z")

</div>

Sorry, now I understand. Here is the data. There are only two rows being it's the weekend.

```python
[
  {
    "Status": "Active",
    "EndOfDownTime": null,
    "StartOfDownTime": {
      "$": [
        "ts",
        192,
        1751214906261
      ],
      "$ts": 1751214816243
    },
    "Duration": 0.02,
    "style": {
      "classes": "flashingRow"
    }
  },
  {
    "Status": "Complete",
    "EndOfDownTime": {
      "$": [
        "ts",
        192,
        1751214906261
      ],
      "$ts": 1751108400023
    },
    "StartOfDownTime": {
      "$": [
        "ts",
        192,
        1751214906261
      ],
      "$ts": 1751086860017
    },
    "Duration": 5.98,
    "style": {
      "classes": "nonFlashingRow"
    }
  }
]

```

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [June 29, 2025, 4:47pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/12 "2025-06-29T16:47:02Z")

</div>

Simplifying one of your row's data for legibility (by removing the time-related columns) you've got,

```python
  {
    "Status": "Active",
    "Duration": 0.02,
    "style": {
      "classes": "flashingRow"
    }
  }

```

That doesn't follow the format I showed in post #2. You need to arrange yours like this,

```python
  {
    "value": {
        "Status": "Active",
        "Duration": 0.02
    },
    "style": {
      "classes": "flashingRow"
    }
  }

```

That's why my post #4 has the line,  
`styled_data.append({"value": row, "style": style)`  
It shoves the whole row of data down a level into the row's `value` property. This is necessary whenever you introduce a style. (Examine the data proprty for the default Table component and see how 'Folsom' is handled - although that's just for a single cell.

---

<div class="post-metadata">

**Author:** ![Steven\_Ham1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven_ham1/32/64482_2.png) [@Steven\_Ham1](https://forum.inductiveautomation.com/u/Steven_Ham1)\
**Post date:** [June 29, 2025, 5:08pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/13 "2025-06-29T17:08:56Z")

</div>

Yes, that was it. Thank you for your help, I was chasing that for a few days. I changed the code to:

```python
styled_data = []

for rowIndex in range(value.getRowCount()):
    row_data = {}
    for colIndex in range(value.getColumnCount()):
        col_name = value.getColumnName(colIndex)
        row_data[col_name] = value.getValueAt(rowIndex, colIndex)

    if row_data.get("Status") == "Active":
        styled_row = {
            "value": row_data,
            "style": { "classes": "flashingRow" }
        }
    else:
        styled_row = {
            "value": row_data,
            "style": {}
        }

    styled_data.append(styled_row)

return styled_data

```

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [June 29, 2025, 5:14pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/14 "2025-06-29T17:14:27Z")

</div>

Good stuff. You can refactor:

```python
styled_data = []

for row_data in value:
    if row_data.get("Status") == "Active": # missing .get edited in.
        styled_data.append({
            "value": row_data,
            "style": { "classes": "flashingRow" }
        })
    else:
         styled_data.append(row_data)

return styled_data

```

Untested!

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [June 29, 2025, 7:55pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/15 "2025-06-29T19:55:35Z")

</div>

> [@Transistor](#):
>
> `row_data("Status")`

Missing a `.get`:  
`row_data.get('Status')`

```python
return [
	{
		"value": row,
		'style': {'classes': "flashingRow"} if row.get('status') == "Active" else {}
	} for row in value
]

```

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [June 29, 2025, 8:29pm UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/16 "2025-06-29T20:29:03Z")

</div>

Thanks, Pascal. I don't think I've ever needed to use `.get`.  
As usual, you've compacted it more than I could!

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [June 30, 2025, 12:12am UTC](https://forum.inductiveautomation.com/t/conditional-row-style/107909/17 "2025-06-30T00:12:19Z")

</div>

> [@Transistor](#):
>
> needed to use `.get`.

When the dictionary might not have that key, `.get()` returns `None` instead of throwing a key error.

(Of course, you might _really_ need it if you get the case of the key wrong.)
