Node-red-node-ui-table redraw table with scrollbar

I have a dashboard table with sufficient rows to need a vertical scrollbar.

The table is automatically refreshed to display the latest data and the scrollbar returns to the top every time.

Is there any way to refresh but leave the scrollbar where it was?

1 Like

Found this in the tabulator documentation, (but the version is 5.5. not sure what version ui-table uses)

Thanks very much for the suggestion @smanjunath211

I can see that they allow for the scrollbar not to reset but the examples are way over my head.

Any ideas how I can apply this in Node-red ui-table?

Hi jbudd, that documentation is Tabulator 5.5 and ui-table is based on 4.7. You may find this more help Tabulator | JavaScript Tables & Data Grids

There are examples in the ui-table example library as how to apply it.

Umm ok, thanks, but I don't know how to use any of that.

I have got a ui-table widget and I'm throwing an array at it now and then.

Maybe this is not possible with the ui-table widget regardless of Tabulator version and I need to look for a solution to wrap inside a template?

Have you looked at the ui-table examples, you would send this in a msg.payload as a command
You would need to save your current row, then when update comes in send command to go back to row position.
e.g.

[{"id":"36be75f0.115c6a","type":"ui_button","z":"d1395164b4eec73e","name":"","group":"c91332c0.50c11","order":1,"width":0,"height":0,"passthru":false,"label":"Init 60rows","tooltip":"init table by passing the hole table array (default way)","color":"","bgcolor":"","className":"","icon":"","payload":"60","payloadType":"num","topic":"","topicType":"str","x":424,"y":4954,"wires":[["d4dce9b4.1f2588"]]},{"id":"d4dce9b4.1f2588","type":"function","z":"d1395164b4eec73e","name":"table with n rows as array","func":"var numberOfRows = msg.payload;\nflow.set(\"lastId\",numberOfRows);\nmsg.payload=[];\nfor (let i=1; i<=numberOfRows; i++) {\n    msg.payload.push({\"id\":i,\"timestamp\":Date.now(),\"text\":\"this is line\"+i})\n}\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":685,"y":4954,"wires":[["b075d2ac.a69f3","f9bfd98.abe1a28"]]},{"id":"b075d2ac.a69f3","type":"ui_table","z":"d1395164b4eec73e","group":"237da972.5d69a6","name":"","order":0,"width":"17","height":"6","columns":[{"field":"id","title":"id","width":"","align":"right","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"timestamp","title":"Timestamp","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"text","title":"Text","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}}],"outputs":1,"cts":true,"x":1010,"y":5000,"wires":[["588f316.0b070d"]]},{"id":"f9bfd98.abe1a28","type":"debug","z":"d1395164b4eec73e","name":"addRow","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":635,"y":5005,"wires":[]},{"id":"eb577b4b.510388","type":"function","z":"d1395164b4eec73e","name":"create command","func":"msg.payload={\n    \"command\": \"scrollToRow\",\n    \"arguments\": [\n        msg.payload, \"nearest\", false\n    ],\n    \"returnPromise\": false\n\n}\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":665,"y":5124,"wires":[["b075d2ac.a69f3"]],"info":"# addRow([row],onTop)\n\n`onTop=true`\n\nadds a new Row on top of the table"},{"id":"588f316.0b070d","type":"debug","z":"d1395164b4eec73e","name":"response from ui-table","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1200,"y":5000,"wires":[]},{"id":"8a654026b3e8e8dd","type":"ui_text_input","z":"d1395164b4eec73e","name":"","label":"scrol to","tooltip":"typr row id","group":"c91332c0.50c11","order":2,"width":0,"height":0,"passthru":false,"mode":"number","delay":"0","topic":"topic","sendOnBlur":true,"className":"","topicType":"msg","x":420,"y":5080,"wires":[["eb577b4b.510388"]]},{"id":"c91332c0.50c11","type":"ui_group","name":"commands","tab":"379a501f.53b59","order":2,"disp":true,"width":"6","collapse":false},{"id":"237da972.5d69a6","type":"ui_group","name":"ui-table with commands","tab":"379a501f.53b59","order":1,"disp":true,"width":"17","collapse":false},{"id":"379a501f.53b59","type":"ui_tab","name":"ui-table command","icon":"fa-table","disabled":false,"hidden":false}]

[edit]
Here is another example that will hold an id position, click the row you wish to be held at a top ( obviously the first 10 rows can never be at top) then reinitialize the table data,the row you clicked will then be the top row.

[{"id":"588f316.0b070d","type":"debug","z":"d1395164b4eec73e","name":"response from ui-table","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1120,"y":5060,"wires":[]},{"id":"36be75f0.115c6a","type":"ui_button","z":"d1395164b4eec73e","name":"","group":"c91332c0.50c11","order":1,"width":0,"height":0,"passthru":false,"label":"Init 60rows","tooltip":"init table by passing the hole table array (default way)","color":"","bgcolor":"","className":"","icon":"","payload":"60","payloadType":"num","topic":"","topicType":"str","x":344,"y":5014,"wires":[["d4dce9b4.1f2588","f72562578f5417ad"]]},{"id":"d4dce9b4.1f2588","type":"function","z":"d1395164b4eec73e","name":"table with n rows as array","func":"var numberOfRows = msg.payload;\nflow.set(\"lastId\",numberOfRows);\nmsg.payload=[];\nfor (let i=40; i<=(numberOfRows+40); i++) {\n    msg.payload.push({\"id\":i,\"timestamp\":Date.now(),\"text\":\"this is line\"+i})\n}\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":605,"y":5014,"wires":[["b075d2ac.a69f3","f9bfd98.abe1a28"]]},{"id":"f72562578f5417ad","type":"change","z":"d1395164b4eec73e","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"row","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":5120,"wires":[["eb577b4b.510388"]]},{"id":"b075d2ac.a69f3","type":"ui_table","z":"d1395164b4eec73e","group":"237da972.5d69a6","name":"","order":0,"width":"17","height":"6","columns":[{"field":"id","title":"id","width":"","align":"right","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"timestamp","title":"Timestamp","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"text","title":"Text","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}}],"outputs":1,"cts":true,"x":930,"y":5060,"wires":[["588f316.0b070d","38c5d8c65ec939fa"]]},{"id":"f9bfd98.abe1a28","type":"debug","z":"d1395164b4eec73e","name":"addRow","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":555,"y":5065,"wires":[]},{"id":"eb577b4b.510388","type":"function","z":"d1395164b4eec73e","name":"create command","func":"msg.payload={\n    \"command\": \"scrollToRow\",\n    \"arguments\": [\n        msg.payload, \"top\", false\n    ],\n    \"returnPromise\": false\n\n}\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":5120,"wires":[["b075d2ac.a69f3"]],"info":"# addRow([row],onTop)\n\n`onTop=true`\n\nadds a new Row on top of the table"},{"id":"38c5d8c65ec939fa","type":"change","z":"d1395164b4eec73e","name":"","rules":[{"t":"set","p":"row","pt":"flow","to":"payload.id","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1030,"y":5000,"wires":[[]]},{"id":"c91332c0.50c11","type":"ui_group","name":"commands","tab":"379a501f.53b59","order":2,"disp":true,"width":"6","collapse":false},{"id":"237da972.5d69a6","type":"ui_group","name":"ui-table with commands","tab":"379a501f.53b59","order":1,"disp":true,"width":"17","collapse":false},{"id":"379a501f.53b59","type":"ui_tab","name":"ui-table command","icon":"fa-table","disabled":false,"hidden":false}]
1 Like

Thanks for the reply @E1cid, trying to find time to look at your example,

I found this

Noting

lets you silently replace all data in the table without updating scroll position,

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

It Works !