UI table row color

Hi all.

I am newbie in node red. I have som little experiences, but not much.So I have read many examples and also imported example ui control of table, but I am not able to create simple function, that highlight a row by red color in the table, that has a value send via flow.set <10.
UI table is readed from DB directly. Here is code. If you can help me, I will be glad. Many thanks for your time.

[
    {
        "id": "13861ca69f2c20b6",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "79f18799d32c03d1",
        "type": "ui_table",
        "z": "13861ca69f2c20b6",
        "group": "ec06941b4e2e607f",
        "name": "",
        "order": 8,
        "width": "25",
        "height": "12",
        "columns": [
            {
                "field": "id",
                "title": "<small>ID</small>",
                "width": "3%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "location",
                "title": "<small>Umiestnenie</small>",
                "width": "12%",
                "align": "left",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "input_rel",
                "title": "<small>Zdroj.relé</small>",
                "width": "",
                "align": "center",
                "formatter": "tickCross",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "charge_rel",
                "title": "<small>Nabíj.relé</small>",
                "width": "",
                "align": "center",
                "formatter": "tickCross",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "output_rel",
                "title": "<small>Výst.relé</small>",
                "width": "",
                "align": "center",
                "formatter": "tickCross",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "output_rel_time",
                "title": "<small>ÄŚas do zap.rel.</small>",
                "width": "",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "batt_volt",
                "title": "<small>U bat.(V)</small>",
                "width": "",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "charge_volt",
                "title": "<small>U nab.(V)</small>",
                "width": "",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "input_volt",
                "title": "<small>U zdroja(V)</small>",
                "width": "",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "charge_curr",
                "title": "<small>I nab.(A)</small>",
                "width": "",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "output_curr",
                "title": "<small>I výst.(A)</small>",
                "width": "",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "charge_status",
                "title": "<small>Stav nab.</small>",
                "width": "",
                "align": "center",
                "formatter": "traffic",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "output_power",
                "title": "<small>P-(W)</small>",
                "width": "6%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "temp_box",
                "title": "<small>T(°C)</small>",
                "width": "5%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "errors_mess",
                "title": "<small>Info/Err</small>",
                "width": "6%",
                "align": "left",
                "formatter": "color",
                "formatterParams": {
                    "target": "_blank"
                }
            }
        ],
        "outputs": 1,
        "cts": true,
        "x": 470,
        "y": 100,
        "wires": [
            [
                "01fac031c65184bc"
            ]
        ]
    },
    {
        "id": "54f34611329ab63f",
        "type": "sqlite",
        "z": "13861ca69f2c20b6",
        "mydb": "77663dac4f64af8e",
        "sqlquery": "msg.topic",
        "sql": "",
        "name": "sqlitedb",
        "x": 300,
        "y": 100,
        "wires": [
            [
                "79f18799d32c03d1"
            ]
        ]
    },
    {
        "id": "6e7912c9adec9a32",
        "type": "inject",
        "z": "13861ca69f2c20b6",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "5",
        "crontab": "",
        "once": true,
        "onceDelay": "2",
        "topic": "SELECT * FROM ups_data ORDER BY id;",
        "payload": "",
        "payloadType": "date",
        "x": 130,
        "y": 100,
        "wires": [
            [
                "54f34611329ab63f"
            ]
        ]
    },
    {
        "id": "f6aedf5c5e1a93f0",
        "type": "ui_toast",
        "z": "13861ca69f2c20b6",
        "position": "dialog",
        "displayTime": "3",
        "highlight": "",
        "sendall": false,
        "outputs": 1,
        "ok": "OK",
        "cancel": "",
        "raw": true,
        "className": "",
        "topic": "",
        "name": "info_panel",
        "x": 690,
        "y": 200,
        "wires": [
            []
        ]
    },
    {
        "id": "01fac031c65184bc",
        "type": "function",
        "z": "13861ca69f2c20b6",
        "name": "function 22",
        "func": "var msg1, msg2, msg3, errs;\nvar sel_row = flow.get(\"db_row_id\");// ID autoincremented by DB\nvar data_extr = msg.payload; // extracted data from payload\nvar info_loc, info_text, info_err;\ninfo_loc = msg.payload.location; // location info from DB\nif (msg.payload.errors_num==0){\nerrs = \"Without err\";       \n} else if (msg.payload.errors_num == 1){\n    errs = \"Battery charging error.\";     \n} else if (msg.payload.errors_num == 2) {\n    errs = \"Low battery capacity.\";\n} else if (msg.payload.errors_num == 3) {\n    errs = \"Battery discarged.\";\n} else if (msg.payload.errors_num == 4) {\n    errs = \"Battery not connected.\";\n} else if (msg.payload.errors_num == 5) {\n    errs = \"Longest duration of battery capacity !\";\n} else if (msg.payload.errors_num == 6) {\n    errs = \"Battery test running\";\n}\ninfo_text = \"<b>IP adr :</b> \" + msg.payload.ris_ip + \"<br><b>ASDU(ID) :</b> \" + msg.payload.ris_id + \"<br><b>Messages :</b> \" + errs;\nmsg1 = { topic: info_loc, payload: info_text};\nmsg1.socketid = msg.socketid;\nreturn [msg1, msg2, msg3];",
        "outputs": 3,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 630,
        "y": 110,
        "wires": [
            [
                "f6aedf5c5e1a93f0"
            ],
            [],
            []
        ]
    },
    {
        "id": "391dfd00f6a932dd",
        "type": "link in",
        "z": "13861ca69f2c20b6",
        "name": "link in 1",
        "links": [
            "4555861d9e04dff6"
        ],
        "x": 275,
        "y": 240,
        "wires": [
            []
        ]
    },
    {
        "id": "ec06941b4e2e607f",
        "type": "ui_group",
        "name": "Dáta UPS",
        "tab": "8971efe7.4a1af",
        "order": 1,
        "disp": true,
        "width": "25",
        "collapse": false,
        "className": ""
    },
    {
        "id": "77663dac4f64af8e",
        "type": "sqlitedb",
        "db": "/home/pi/SmartUPS/db_data_ups.sqlite",
        "mode": "RW"
    },
    {
        "id": "8971efe7.4a1af",
        "type": "ui_tab",
        "name": "Main view",
        "icon": "fa-bar-chart",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

I understand that you are using the table node of dashboard-1. You say you are a newbie - why not start with dashboard-2? (dashboard-1 is no longer supported, and specifically, its table node does not support custom formatting functions).

In dashboard-2, you have 2 options:

  1. Use the basic table node, which is based on Vue. It gives you basic functionality, and you can set conditional formatting by providing a row-props function in your data area which returns a CSS class/style based on the row data.

  2. Alternatively, you can use the much more powerful @omrid/node-red-dashboard-2-table-tabulator node , which is based on the same engine as in D-1 (Tabulator), and fully supports internal functions and conditional formatting (see the on-line help and provided examples).

Thanks Omrid for your help. Your package is not possible to install at me, wrotes me :

So there is an error : Unsuported engine.
Except it, your first select is possible. But I do not found any row props and how is possible to applicate to my code. At this moment I have installed DB2 from flowfuse. Also I have connected it to DB and its nice, but without a row-props specifications.

'unsupported engine' typically relates to NPM version compatibility.
Try this:

  • Open a command-line terminal (with admin rights)
  • Go to your Node-red home directory, e.g. \Users<username>.node-red (Windows) or ~/.node-red (Mac or Linux)
  • type NPM install @omrid/node-red-dashboard-2-table-tabulator

You are running an old version of node.js. Which also means that you are likely running an old version of Node-RED?

Please update to the current version of Node-RED but you will first need to update Node.js to at least v18.20 - v22 LTS is the current recommended version.

Once you are able to install ui-tabulator, I would highly recommend importing the sample flows that @omrid has created. Those are a good starting point to see how to configure, populate and interact with ui-tablulator.

Here is the link to the examples (on GitHub) ui-tabulator sample flows

Note that, for every node which includes examples, you can import them directly from the 'import' dialog

1 Like

Oh yes! Completely forgot about that :man_facepalming:t2:

I have a nodered v.3.0.2 and node.js version 16.20.2

OK, now I have updated it to nr 4.1 and node.js 22. At this moment I have installed Omri’s package of tabulator. Example looks nice.
If I return to my first post, how do I add to function node this settings and how can I identify a row number, which must be colored based on input value set by flow.set ?
In PHP is not problem for me, but I am not professional in json and javascripts. Thanks to help.

I can't help with that I'm afraid as I don't really use Dashboard 2 or the tabulator node for it. (I am the author of UIBUILDER).

However, I think that there may have been some recent posts related to tabulator node and that may help. Also check for any examples (ctrl+i to get the import dialog, check the examples and look for the tabulator node).

Oh, I understand. May be @omrid could help me. So, big thanks to right direction, that help me solved part of problems.

OK, here's an example. In ui-tabulator, let's assume you have a column "age", and you want red background color for every row in which age<18.

  1. In the table configuration, add a row formatter, which will dynamically set the row background color to red if age<18. The formatter will be called ageColor, and will be prefixed by @F: to indicate that it is a function.
{
   "height": 300,
   "columns": [...],
   "data": [...],
   "rowFormatter":"@F:ageColor"
}
  1. Now define the actual function body in the Custom Functions area:
function ageColor (row)
{
    if (row.getData().age < 18)
       row.getElement().style.backgroundColor = "red";
}

That's it. Just change it to your required logic.

1 Like

Thanks for help me. So I am trying it at this moment.
I took one else problem. My nodes looks like this :

Function node has a code :

msg.tbArgs = [ [	 		{ id: msg.payload.id, location: msg.payload.location, errors_num: msg.payload.errors_num}, 	] ] return msg; 

Tabulator node has a code :

{
   "height": 200,
   "selectableRows": true,
   "layout": "fitColumns",
   "data": [
    "msg.payload" 
   ],
   "columns": [
      {
         "title": "Id",
         "field": "id",
         "width": "3%",
         "headerSortTristate": true,
         "hozAlign": "center"
      },
      {
         "title": "Location",
         "field": "location",
         "width": "10%",
         "headerSortTristate": true,
         "hozAlign": "left",
         "headerFilter": "input",
         "headerFilterPlaceholder": "Filter..."
      },
      {
         "title": "ASDU add.",
         "field": "ris_id",
         "width": "5%",
         "headerSortTristate": true,
         "hozAlign": "left",
         "headerFilter": "input",
         "headerFilterPlaceholder": "Filter..."
      }
      
   ]
}

So I think, that is not correct, but definition this is for me too difficult, than I will understand. Thanks for your time.

Bohumil

I did it. Wau.

Function node code :

msg.tbCmd = "setData";
msg.tbArgs = [
msg.payload
]
return msg;

Tabulator node :

{
	"height": 200,
	"selectableRows": false,
    "layout":"fitColumns",
	"data": [
		"msg.tbArgs"		
	],
	"columns": [
		{
			"title": "Id",
			"field": "id",
			"width": "5%",
			"headerSortTristate":false,
			"hozAlign": "center"
		},
		{
			"title": "Location",
			"field": "location",
			"width": "15%",
			"headerSortTristate":false,
			"hozAlign": "left",
			"headerFilter": "input",
			"headerFilterPlaceholder": "Filter..."
		},
		{
			"title": "Messages",
			"field": "errors_num",
			"width": "8%",
			"headerSortTristate":false,
			"hozAlign": "left",
			"formatter": "@F:errColor",
			"formatterParams": {
				"minErr": 1
			}
		
		},
		{
			"title": "Inp.relay",
			"field": "input_rel",
			"width": "5%",
			"headerSortTristate": false,
			"hozAlign": "center",
			"formatter": "traffic",
			"formatterParams": {
				"min": 0,
				"max": 1,
				"color": [
					"red",
					"green"
				]
			}
		},
		{
			"title": "Chrg.relay",
			"field": "charge_rel",
			"width": "5%",
			"headerSortTristate": false,
			"hozAlign": "center",
			"formatter": "traffic",
			"formatterParams": {
				"min": 0,
				"max": 1,
				"color": [
					"red",
					"green"
				]
			}
		},
		{
			"title": "Out relay",
			"field": "output_rel",
			"width": "5%",
			"headerSortTristate": false,
			"hozAlign": "center",
			"formatter": "traffic",
			"formatterParams": {
				"min": 0,
				"max": 1,
				"color": [
					"red",
					"green"
				]
			}
		}
	]
}

And Custom functions :

function errColor(cell, params) {
    // Conditional formatter
    if (cell.getValue() < params.minErr){
   cell.getElement().style.color = 'green';     
    }else{
cell.getElement().style.color = 'red';
    }
        
    return cell.getValue();
}

So I am happy and big thanks @omrid and all colleagues.

If your table definition is in the ui-tabular configuration, I don’t think you need to to specify this. In my setup, I have the table definition and mapping col/field in the ui_tabulator configuration and I just send in msg.tbCmd=”setData” and msg.tbArgs=msg.payload from a change node.

@rakgupta is correct. The node's table configuration is applied when the node is created - before any message is sent or received, so data: [msg.tbArgs] is undefined and ignored. Just remove it.

Thanks to both @omrid and @rakgupta for clearing me this process. I am in study mode and all informations about this type of dashboard and its nodes are really new for me.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.