Why does change node with set msg.payload to msg.payload solves unintended behavior?

Hello together,

I had problems with the uiTable not updating automaticly the ui correctly (F5 required). The only difference to the working example was that I collected my message with the data manually in a function node beforehand. The output there was for my eyes identical to the working example.
However, it didn't work ...

Workaround was to insert a stupid change node in between without obviously changing at all in the message: "set msg.payload to msg.payload"

However, something unknown changed nevertheless and the uiTable now accepts the messages passed through the change node in the intended way and updates automatically.

Any ideas? What did I miss?

Best regards

Moppel

The picture shows both, the not working flow above, and the working flow below:

Version: 3.0.2 läuft auf Windows10 lokal.
node-red-node-ui-table: 0.4.3
node-red-dashboard: 3.4.0

JSON Setting

Summary
[
    {
        "id": "2ee9f5ba8157e4bb",
        "type": "tab",
        "label": "General",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "2de85b8dc544e93a",
        "type": "change",
        "z": "2ee9f5ba8157e4bb",
        "name": "ui_control",
        "rules": [
            {
                "t": "set",
                "p": "ui_control",
                "pt": "msg",
                "to": "{\"tabulator\":{\"columnResized\":\"function(column){     var newColumn = {         field: column._column.field,         visible: column._column.visible,         width: column._column.width,         widthFixed: column._column.widthFixed,         widthStyled: column._column.widthStyled     }; this.send({topic:this.config.topic,ui_control:{callback:'columnResized',columnWidths:newColumn}}); }\",\"columnMoved\":\"function(column, columns){     var newColumns=[x];     columns.forEach(function (column) {         newColumns.push({'field': column._column.field});     });     this.send({topic:this.config.topic,ui_control:{callback:'columnMoved',columns:newColumns}}); }\",\"groupHeader\":\"function (value, count, data, group) {return value + \\\"<span style='color:#d00; margin-left:10px;'>(\\\" + count + \\\" Termostat\\\"+((count>1) ? \\\"e\\\" : \\\"\\\") + \\\")</span>\\\";}\",\"columns\":[{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"ROom\",\"field\":\"room\",\"width\":100,\"frozen\":true},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Device\",\"field\":\"name\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Type\",\"field\":\"deviceType\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Measurements\",\"columns\":[{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"target\",\"field\":\"SET_TEMPERATURE-value\",\"formatter\":\"function(cell, formatterParams, onRendered){return cell.getValue()+'°C';}\",\"topCalc\":\"avg\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"min\":10,\"max\":25,\"color\":[\"blue\",\"green\",\"red\"],\"legend\":\"function (value) {return '&nbsp;&nbsp;'+value+'°C';}\",\"legendColor\":\"#101010\",\"legendAlign\":\"left\"},\"title\":\"current\",\"field\":\"ACTUAL_TEMPERATURE-value\",\"formatter\":\"progress\",\"topCalc\":\"avg\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"min\":0,\"max\":99,\"color\":[\"gray\",\"orange\",\"red\"],\"legend\":\"function (value) {return (value>0)? '&nbsp;&nbsp;'+value+' %' : '-';}\",\"legendColor\":\"#101010\",\"legendAlign\":\"center\"},\"title\":\"Valve\",\"field\":\"VALVE_STATE-value\",\"formatter\":\"progress\",\"topCalc\":\"max\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"min\":1.5,\"max\":4.6,\"color\":[\"red\",\"orange\",\"green\"],\"legend\":\"function (value) {return value+' V';}\",\"legendColor\":\"#101010\",\"legendAlign\":\"center\"},\"title\":\"Batt\",\"field\":\"BATTERY_STATE-value\",\"formatter\":\"progress\",\"topCalc\":\"min\",\"width\":100}]},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Settings\",\"columns\":[{\"formatterParams\":{\"target\":\"_blank\",\"min\":0,\"max\":30,\"color\":[\"red\",\"orange\",\"green\"],\"legend\":\"function (value) {     if (value>0)         return \\\"<span style='color:#101010;'>\\\"+value+\\\" min</span>\\\";     else         return \\\"<span style='color:#A0A0A0;'>aus</span>\\\"; }\",\"legendColor\":\"#101010\",\"legendAlign\":\"center\"},\"title\":\"Boost\",\"field\":\"BOOST_STATE-value\",\"formatter\":\"progress\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"allowEmpty\":true,\"allowTruthy\":true,\"tickElement\":\"<i class='fa fa-clock-o'></i>\",\"crossElement\":\"<i class='fa fa-ban'></i>\"},\"title\":\"Auto\",\"field\":\"AUTO_MODE-value\",\"formatter\":\"tickCross\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Mode\",\"field\":\"CONTROL_MODE-value\",\"formatter\":\"function(cell, formatterParams, onRendered){     var html=\\\"<i class=\\\\\\\"\\\";     switch(cell.getValue()) {         case 0: html+=\\\"fa fa-calendar-check-o\\\"; break;         case 1: html+=\\\"fa fa-hand-o-up\\\"; break;         case 2: html+=\\\"fa fa-suitcase\\\"; break;         case 3: html+=\\\"fa fa-spinner fa-spin fa-fw\\\"; break;     }     html+='\\\\\\\"></i>';     return html; }\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Auto\",\"field\":\"AUTO_MODE-value\",\"formatter\":\"tick\",\"width\":100,\"align\":\"center\"}]}],\"layout\":\"fitColumns\",\"movableColumns\":true,\"groupBy\":\"\"},\"customHeight\":12}",
                "tot": "json"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 360,
        "y": 720,
        "wires": [
            [
                "3a632cada5efcde9"
            ]
        ]
    },
    {
        "id": "07eb107a9a3145d0",
        "type": "debug",
        "z": "2ee9f5ba8157e4bb",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 673,
        "y": 720,
        "wires": []
    },
    {
        "id": "3a632cada5efcde9",
        "type": "ui_table",
        "z": "2ee9f5ba8157e4bb",
        "group": "51ce6aa1.620754",
        "name": "Thermostats",
        "order": 1,
        "width": "20",
        "height": "7",
        "columns": [],
        "outputs": 1,
        "cts": true,
        "x": 523,
        "y": 720,
        "wires": [
            [
                "07eb107a9a3145d0"
            ]
        ]
    },
    {
        "id": "f94324184fb9b3cc",
        "type": "function",
        "z": "2ee9f5ba8157e4bb",
        "name": "Collect in array and send all at once",
        "func": "var tableData = flow.get(\"tableData\");\nif (tableData === undefined) {\n    tableData = [];\n    flow.set(\"tableData\", tableData);\n    node.error(\"Empty table, created new one\", msg);\n}\n\ntableData.unshift(msg.payload);\nflow.set(\"tableData\", tableData);\n\nmsg = {}\nmsg.payload = tableData\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 340,
        "y": 640,
        "wires": [
            [
                "ee6bec1453428580",
                "5cbf121f8f0a9678"
            ]
        ]
    },
    {
        "id": "842c8741ef293899",
        "type": "inject",
        "z": "2ee9f5ba8157e4bb",
        "name": "Add one entry",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{\"name\":\"MEQ1875547\",\"room\":\"Living Room\",\"SET_TEMPERATURE-value\":12,\"ACTUAL_TEMPERATURE-value\":16.2,\"VALVE_STATE-value\":0,\"BATTERY_STATE-value\":2.7,\"BOOST_STATE-value\":0,\"AUTO_MODE-value\":false,\"CONTROL_MODE-value\":1}",
        "payloadType": "json",
        "x": 110,
        "y": 640,
        "wires": [
            [
                "f94324184fb9b3cc"
            ]
        ]
    },
    {
        "id": "ee6bec1453428580",
        "type": "change",
        "z": "2ee9f5ba8157e4bb",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 200,
        "y": 720,
        "wires": [
            [
                "2de85b8dc544e93a"
            ]
        ]
    },
    {
        "id": "5cbf121f8f0a9678",
        "type": "change",
        "z": "2ee9f5ba8157e4bb",
        "name": "ui_control",
        "rules": [
            {
                "t": "set",
                "p": "ui_control",
                "pt": "msg",
                "to": "{\"tabulator\":{\"columnResized\":\"function(column){     var newColumn = {         field: column._column.field,         visible: column._column.visible,         width: column._column.width,         widthFixed: column._column.widthFixed,         widthStyled: column._column.widthStyled     }; this.send({topic:this.config.topic,ui_control:{callback:'columnResized',columnWidths:newColumn}}); }\",\"columnMoved\":\"function(column, columns){     var newColumns=[];     columns.forEach(function (column) {         newColumns.push({'field': column._column.field});     });     this.send({topic:this.config.topic,ui_control:{callback:'columnMoved',columns:newColumns}}); }\",\"groupHeader\":\"function (value, count, data, group) {return value + \\\"<span style='color:#d00; margin-left:10px;'>(\\\" + count + \\\" Termostat\\\"+((count>1) ? \\\"e\\\" : \\\"\\\") + \\\")</span>\\\";}\",\"columns\":[{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"ROom\",\"field\":\"room\",\"width\":100,\"frozen\":true},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Device\",\"field\":\"name\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Type\",\"field\":\"deviceType\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Measurements\",\"columns\":[{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"target\",\"field\":\"SET_TEMPERATURE-value\",\"formatter\":\"function(cell, formatterParams, onRendered){return cell.getValue()+'°C';}\",\"topCalc\":\"avg\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"min\":10,\"max\":25,\"color\":[\"blue\",\"green\",\"red\"],\"legend\":\"function (value) {return '&nbsp;&nbsp;'+value+'°C';}\",\"legendColor\":\"#101010\",\"legendAlign\":\"left\"},\"title\":\"current\",\"field\":\"ACTUAL_TEMPERATURE-value\",\"formatter\":\"progress\",\"topCalc\":\"avg\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"min\":0,\"max\":99,\"color\":[\"gray\",\"orange\",\"red\"],\"legend\":\"function (value) {return (value>0)? '&nbsp;&nbsp;'+value+' %' : '-';}\",\"legendColor\":\"#101010\",\"legendAlign\":\"center\"},\"title\":\"Valve\",\"field\":\"VALVE_STATE-value\",\"formatter\":\"progress\",\"topCalc\":\"max\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"min\":1.5,\"max\":4.6,\"color\":[\"red\",\"orange\",\"green\"],\"legend\":\"function (value) {return value+' V';}\",\"legendColor\":\"#101010\",\"legendAlign\":\"center\"},\"title\":\"Batt\",\"field\":\"BATTERY_STATE-value\",\"formatter\":\"progress\",\"topCalc\":\"min\",\"width\":100}]},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Settings\",\"columns\":[{\"formatterParams\":{\"target\":\"_blank\",\"min\":0,\"max\":30,\"color\":[\"red\",\"orange\",\"green\"],\"legend\":\"function (value) {     if (value>0)         return \\\"<span style='color:#101010;'>\\\"+value+\\\" min</span>\\\";     else         return \\\"<span style='color:#A0A0A0;'>aus</span>\\\"; }\",\"legendColor\":\"#101010\",\"legendAlign\":\"center\"},\"title\":\"Boost\",\"field\":\"BOOST_STATE-value\",\"formatter\":\"progress\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"allowEmpty\":true,\"allowTruthy\":true,\"tickElement\":\"<i class='fa fa-clock-o'></i>\",\"crossElement\":\"<i class='fa fa-ban'></i>\"},\"title\":\"Auto\",\"field\":\"AUTO_MODE-value\",\"formatter\":\"tickCross\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Mode\",\"field\":\"CONTROL_MODE-value\",\"formatter\":\"function(cell, formatterParams, onRendered){     var html=\\\"<i class=\\\\\\\"\\\";     switch(cell.getValue()) {         case 0: html+=\\\"fa fa-calendar-check-o\\\"; break;         case 1: html+=\\\"fa fa-hand-o-up\\\"; break;         case 2: html+=\\\"fa fa-suitcase\\\"; break;         case 3: html+=\\\"fa fa-spinner fa-spin fa-fw\\\"; break;     }     html+='\\\\\\\"></i>';     return html; }\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Auto\",\"field\":\"AUTO_MODE-value\",\"formatter\":\"tick\",\"width\":100,\"align\":\"center\"}]}],\"layout\":\"fitColumns\",\"movableColumns\":true,\"groupBy\":\"\"},\"customHeight\":12}",
                "tot": "json"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 360,
        "y": 580,
        "wires": [
            [
                "eab1bdd0731c9de8"
            ]
        ]
    },
    {
        "id": "e668a97759ce7766",
        "type": "debug",
        "z": "2ee9f5ba8157e4bb",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 673,
        "y": 580,
        "wires": []
    },
    {
        "id": "eab1bdd0731c9de8",
        "type": "ui_table",
        "z": "2ee9f5ba8157e4bb",
        "group": "51ce6aa1.620754",
        "name": "Thermostats",
        "order": 1,
        "width": "20",
        "height": "7",
        "columns": [],
        "outputs": 1,
        "cts": true,
        "x": 523,
        "y": 580,
        "wires": [
            [
                "e668a97759ce7766"
            ]
        ]
    },
    {
        "id": "51ce6aa1.620754",
        "type": "ui_group",
        "name": "ui_control",
        "tab": "3b08fac0.8f06b6",
        "order": 1,
        "disp": true,
        "width": "22",
        "collapse": false
    },
    {
        "id": "3b08fac0.8f06b6",
        "type": "ui_tab",
        "name": "Home",
        "icon": "track_changes",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

Try using this as the function node:

let tableData = flow.get("tableData") || [];

if (tableData === undefined) {
    tableData = [];
    flow.set("tableData", tableData);
    node.error("Empty table, created new one", msg);
}

tableData.unshift(msg.payload);

flow.set("tableData", tableData);

msg = {}
msg.payload = tableData
return msg;

and get rid of the set msg.payload change node

I don't believe that will ever be triggered because you've included || [] so it will never be undefined. You might instead need: if (tableData.length === 0) {

Well looking at the code, that IF statement code group isn't even needed however it would be a good idea to validate that msg.payload is an array.

The work around you found seems only to work if you have two tables. Some form of bug that refreshes the second table.

You should really send a command to replace data

msg.payload = {
    command:"replaceData",
    arguments: 
    [tableData]
}

Or add rows there are examples in the editor
import > examples > ui-table

Hello together,

thank you for your responses, trying to help.

@TotallyInformation & Zenofmud: I agree, that the if statement could be omitted or that there are nicer ways describing it. However, I thing this code section is not the core problem of the mysterious behavior. By the way, the if section is almost copied 1:1 from the uiTable command example :slight_smile:

@E1cid:
Wow, I didn't know that it only works with the second uiTable by chance. Then my solution looks more like a bug which cancels a bug ... --> Not reliable.

Thanks for pointing out the example with the "Commands". I tried it the night before, but didn't like it due to its overhead in preserving data and keeping track of the ID if deleting a row is required.
Just filling the table with all data each time seemed easier as in the ui_control example. If I use that example it and feed the uiTable with different inject buttons (and different data in each) it works fine. But if I want to dynamically build up the data stack I ended with above problems. I don't know what's the reason for that. The messages are pure identically except the msgID.

However, you pointed the "replaceData" command out. That might be right compromise here. Thanks you very much. I will give it a try!

replaceData also has a benefit of maintaining the scroll position when new data arrives and you are view the table

hi E1cid,
hi uiTable beginners,

I crunched provided snippets and got successful in two different ways to update an uiTable at once with a full list. I will mark my answer as "Solution", however it is heavily based on E1cid answer and pushed by the help of the community here:

Difference in user experience

  1. Possibility "replaceData": Viewport remains unchaned if new data comes in.

  2. Possibility "As in 'Command-Example'" of uiTable: Resets viewport.

Differences in programmer experience

  1. Possibility "replaceData": Sends the data with "replace Data" command to the table. For persistence reason, however, I assembly my list in the Flows(!) "tableData" variable of the example flow. It works, but is for sure unintended by the designer :slight_smile:

  2. Possibility "As in 'Command-Example'" of uiTable: It is aligned to the 'init with 20 rows' example. I assemble my own list and take care for its lifecycle. After eachs update I send its content as array AND to the tableData-Persistent node as done in the init-fill example.

BOTH possibilities allows in principle the usage of the other commands.

Thank you all!
Moppel

Example flow Possibility 1:

Example flow Possibility 2:

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