Ui_table not refreshing. Wanted to know if someone else is able to reproduce the issue

I found a strange behaviour when using the ui_table node. I can fix the code in two different ways. The first workaround will fix it in definitive but I don´t know why it works. The second way will fix it in a surprising way but when I roll back the solution is not possible to observe the issue again (surprisingly too).

Before I explain the fixes can someone be kind enough to try to confirm the issue. I want to make sure it is not specific to my environment in the the first place.

This is the minimum flow I could write to try to reproduce the issue.

The first inject node initializes an array of objects and pass it to the ui_table.
I added three more inject nodes to be able to modify data dynamically.

At the initialization the table will be populated as below.

Now, try to clik on the other inject buttons, one at a time. Do you see any update in the column "Power" in the dashboard while after pressing the last three inject nodes ?

Testing flow:

[{"id":"23737d07.4f1e22","type":"tab","label":"Flow 8","disabled":false,"info":""},{"id":"cb321e5a.ad2e5","type":"ui_table","z":"23737d07.4f1e22","group":"e18d18ee.a6f4f8","name":"Grid","order":2,"width":"16","height":"6","columns":[],"outputs":0,"cts":false,"x":1230,"y":340,"wires":[]},{"id":"20a7e1d9.0d10de","type":"function","z":"23737d07.4f1e22","name":"Change object","func":"// grid is an array of objects\nlet grid = flow.get(\"gridmem\") || [];\n\n\n// Find index of Sensor\nlet sRow = grid.findIndex(\n    (ele,index) => ele.Sensor == msg.payload.Sensor\n);\n\n\n// Add a dynamic prperty to the array element\ngrid[sRow][\"Power\"] = \"voltage * current\";\n\n// store modified array to the context\nflow.set(\"gridmem\", grid);\n\nnode.warn(grid);\n\nmsg.payload = grid; //BAD ?\n\n//msg.payload = [...grid]; // Always OK\n\nreturn msg;","outputs":1,"noerr":0,"x":560,"y":340,"wires":[["db2bbd3.7b40f4","e63ac256.0764f","6e8362f0.ccc5fc","8a75d2a5.2752f"]]},{"id":"ec6b8a10.0f9508","type":"inject","z":"23737d07.4f1e22","name":"Change sensor S1","topic":"","payload":"{\"City\":\"Albany\",\"Sensor\":\"S1\",\"Voltage\":220,\"Current\":10}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":330,"y":280,"wires":[["20a7e1d9.0d10de"]]},{"id":"e63ac256.0764f","type":"debug","z":"23737d07.4f1e22","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload[0].Power","targetType":"msg","x":840,"y":400,"wires":[]},{"id":"25908860.5df998","type":"inject","z":"23737d07.4f1e22","name":"Initialize sensors S1, S2, S3","topic":"","payload":"[{\"City\":\"A\",\"Sensor\":\"S1\",\"Voltage\":0,\"Current\":0,\"Power\":0},{\"City\":\"A\",\"Sensor\":\"S2\",\"Voltage\":0,\"Current\":0,\"Power\":0},{\"City\":\"A\",\"Sensor\":\"S3\",\"Voltage\":0,\"Current\":0,\"Power\":0}]","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":360,"y":220,"wires":[["b6b4592.77713a8"]]},{"id":"b6b4592.77713a8","type":"change","z":"23737d07.4f1e22","name":"","rules":[{"t":"set","p":"gridmem","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":220,"wires":[["db2bbd3.7b40f4"]]},{"id":"a030f51d.f62e58","type":"inject","z":"23737d07.4f1e22","name":"Change sensor S2","topic":"","payload":"{\"City\":\"Albany\",\"Sensor\":\"S2\",\"Voltage\":220,\"Current\":20}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":330,"y":340,"wires":[["20a7e1d9.0d10de"]]},{"id":"b6ae383c.350c28","type":"inject","z":"23737d07.4f1e22","name":"Change sensor S3","topic":"","payload":"{\"City\":\"Albany\",\"Sensor\":\"S3\",\"Voltage\":220,\"Current\":30}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":330,"y":400,"wires":[["20a7e1d9.0d10de"]]},{"id":"6e8362f0.ccc5fc","type":"debug","z":"23737d07.4f1e22","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload[1].Power","targetType":"msg","x":840,"y":460,"wires":[]},{"id":"8a75d2a5.2752f","type":"debug","z":"23737d07.4f1e22","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload[2].Power","targetType":"msg","x":840,"y":520,"wires":[]},{"id":"db2bbd3.7b40f4","type":"change","z":"23737d07.4f1e22","name":"ui_control","rules":[{"t":"set","p":"ui_control.tabulator.columns","pt":"msg","to":"[{\"title\":\"City\",\"field\":\"City\"},{\"title\":\"Sensor\",\"field\":\"Sensor\"},{\"title\":\"Voltage\",\"field\":\"Voltage\"},{\"title\":\"Current\",\"field\":\"Current\"},{\"title\":\"Power\",\"field\":\"Power\"}]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":1060,"y":340,"wires":[["cb321e5a.ad2e5"]]},{"id":"e18d18ee.a6f4f8","type":"ui_group","z":"","name":"G2","tab":"783458b.f2fefa8","order":1,"disp":false,"width":"28","collapse":false},{"id":"783458b.f2fefa8","type":"ui_tab","z":"","name":"GRID","icon":"dashboard","disabled":false,"hidden":false}]

The function node is not properly updating the flow variable. add this
node.warn("grid="+JSON.stringify(grid))
just before you flow.set gridmem

I don't see any updates to the table. (macOS - nr 1.0.6 node.js v12.13.0)

@Andrei I've been using the template node to set up my tables. Try this coming from your function nde to the ui_table

[{"id":"fca2f528.50ba9","type":"template","z":"713674da.4fe26c","name":"","field":"ui_control","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n    {\n        \"title\": \"City\",\n        \"field\": \"City\"\n    },\n    {\n        \"title\": \"Sensor\",\n        \"field\": \"Sensor\"\n    },\n    {\n        \"title\": \"Voltage\",\n        \"field\": \"Voltage\"\n    },\n    {\n        \"title\": \"Current\",\n        \"field\": \"Current\"\n    },\n    {\n        \"title\": \"Power\",\n        \"field\": \"Power\"\n    }\n]\n{\n    \"tabulator\": {\n        \"layout\": \"fitDataFill\",\n        \"columns\": [\n    {\n        \"title\": \"City\",\n        \"field\": \"City\"\n    },\n    {\n        \"title\": \"Sensor\",\n        \"field\": \"Sensor\"\n    },\n    {\n        \"title\": \"Voltage\",\n        \"field\": \"Voltage\"\n    },\n    {\n        \"title\": \"Current\",\n        \"field\": \"Current\"\n    },\n    {\n        \"title\": \"Power\",\n        \"field\": \"Power\"\n    }\n        ]\n    }\n}","output":"str","x":1060,"y":240,"wires":[["cb9e2edd.ea089"]]}]

it also lets me do some interesting things ;ile this function node for setting colors of cells

var arr = msg.payload

// set the colors to use
var awake_color  = "LightGreen"
var offline_color = "LightPink"
var sleep_color   = "aqua"
var no_color     = "none"

// framework for the html statement
var row_start     = "<div style='background-color: "
var row_mid       = "'>"
var row_end       = "</div>"

var status_html = ''

// loop thru the array and set the cell's background color based on "node_status"
var arr_len = arr.length
for (var i = 0; i < arr_len; i++) {
    switch (arr[i].node_status) {
        case 'online':
        case 'awake':
            row_color = awake_color  
            break;
        case 'offline':
            row_color = offline_color  
            break;
        case 'sleep':
            row_color = sleep_color  
            break;
        default:
            row_color = no_color  
            break;
    }
    // now build the html for the cell
    html_status = row_start+row_color+row_mid+arr[i].node_status+row_end
    arr[i].node_status = html_status
}
msg.payload = arr
return msg;

oh, here is my template node that goes with that function node

{
    "tabulator": {
        "layout": "fitDataFill",
        "columns": [
            {
                "title": "Node",
                "field": "node_id"
            },
            {
                "title": "Location",
                "field": "location"
            },
            {
                "formatter": "html",
                "title": "Status",
                "field": "node_status"
            },
            {
                "formatter": "datetime",
                "formatterParams": {
                    "inputFormat": "x",
                    "outputFormat": "hh:mm:ss",
                    "invalidPlaceholder": ""
                },
                "title": "Sleep Till",
                "field": "sleep_till"
            },
            {
                "formatter": "datetime",
                "formatterParams": {
                    "inputFormat": "x",
                    "outputFormat": "MM/DD/YY hh:mm:ss",
                    "invalidPlaceholder": ""
                },
                "title": "Last Seen",
                "field": "last_seen"
            },
            {
                "title": "MQTT",
                "field": "mqtt_mode"
            },
            {
                "title": "Temp",
                "field": "temperature",
                "align": "center",
                "formatter": "html"
            }
        ]
    }
}

@zenofmud, Hi Paul. Thanks a lot for your feedback as well as for the examples from your second post. I have an item in my todo list to add a background color to the cell depending on the power consumption of the device . It seems to me that one of your examples does exactly that. I will try it this afternoon.

I tested the node.warn you proposed and found out that the message is being updated as I expect. The funcion node is adding the string voltage*current as it should. But again, the table is not updated, even if it is receiving an updated message.

Now the first way to fix this is to replace below line in the funcion node:

msg.payload = grid; //BAD ?
//msg.payload = [...grid]; // Always OK

Comment the first one and uncomment the second one and all will be fixed. I still have to understand why copying the object this way fix the issue. The default context storage in this computer is the file system. The other way to fix is unbelievable weird. I need to understand better before even disclosing what I did.

Does the grid object get modified by anything downstream? If so is it modifying the one in context too? The copy would stop that.

Hi @Colin, no. There is no modifications between the function node and the ui_table node. There is only a change node in between that defines the columns and only that).

Are you expecting Power to be current * voltage? Beasue in the function you are asigning Power to the string "current * power"

I guess I confused about what you are trying to do.

Yes, Paul. I am just adding a string in this minimum flow as the purpose is to understand the table refresh issue only. It is not my intention to multiple voltage and current to get the power.

I just noticed something. If I delete the flow variable to start fresh. I then click the 'Initilize' button, the table comes up with all zeros.
If I now press one of the three switches, nothing changes on the table

BUT if I do window refresh it does show the string in the table..

So an auto refresh is not happening.

It does, I agree. I just wanted to find how to auto refresh. I could use an ui_control to node to force a refresh (already tested ok) but that would be a last resort.

PS: thanks again for the coloring function. Working fine.

did you try using the template node I posted? With that the change shows as soon as you press the inject button

No I didn´t. I will give it a try. If it works then this will give me some clue on the refresh behaviour.

set it up like this since the ui_control is defining the table.

2 Likes

Hi Paul, indeed. You nailed it. It is working.

I configured th output of the template node as below:

a-4

I will play a little bit more with this config. I am inclined to start using template nodes as it seems they are also good when we need to write callbacks for the ui_table.

Huge thanks !!!

1 Like

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