That is certainly one way you can do it. One minor tweak you might find helpful. If you aren't using a library like old jQuery that already assigns the $
window variable, uibuilder assigns it itself but it uses the more generic document.querySelector(cssSelector)
function.
So you can do:
const eMsg = $(`#${msg.topic}`)
if (eMsg) eMsg.innerHTML = msg.payload
Which you may find a bit easier to work with and is slightly more robust. You could also use innerText
if you only want text and not HTML.
HOWEVER, you could also drive this from Node-RED directly by sending a message containing a msg._ui
property containing this JSONata:
[
{
"method": "update",
"components": [
{
"id": topic,
"slot": payload
}
]
}
]
Here is a flow snippet that will do just that - it contains just an inject node with the data and a change node with the config. Hopefully enough for you to be able to expand it to your own needs.
[{"id":"a3d191ab9281d165","type":"inject","z":"225a6af5f8bc4cc2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"more","payload":"\"This is the dynamic number: \" & \t$formatInteger($random() * 100, \"0\")","payloadType":"jsonata","x":250,"y":860,"wires":[["ccbaf9391f9ea3bb"]]},{"id":"ccbaf9391f9ea3bb","type":"change","z":"225a6af5f8bc4cc2","name":"","rules":[{"t":"set","p":"_ui","pt":"msg","to":"[\t {\t \"method\": \"update\",\t \"components\": [\t {\t \"id\": topic,\t \"slot\": payload\t }\t ]\t }\t]","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":430,"y":860,"wires":[["a176947e40e66640"]]}]
Also worth noting that when v6.1 gets released, this will be even easier because of the new node uib-update
.
In addition, the msg._ui
configuration schema lets you add and remove new HTML dynamically, not just update. At the end of this entry is a flow just containing a bunch of inject nodes that will show you the fun you can have.
These methods have some other advantages too - they can be chained so you can build up a complex set up adds/removes/updates and send them all at once. You can also add a couple of helper libraries that allow the use of Markdown, not just sending text/html and that will sanitise any resulting HTML if you need to allow user input that might be abused.
Yes, please refer to the "First Timer's Walkthrough" in the documentation. However, please be patient because it is being reworked with the fine help of @mudwalker and should be a lot clearer in v6.1 - if you want to take an early look: https://github.com/TotallyInformation/node-red-contrib-uibuilder/blob/v6.1.0/docs/walkthrough1.md
Better still, if you can be bothered, try running up a test instance of Node-RED and install the uibuilder v6.1.0 branch into it. Then you can try out the new features and access the updated documentation directly.
Example flow snippet showing how you can create and manipulate HTML from Node-RED using uibuilder's low-code schema.
[{"id":"62d58bb53910ec63","type":"inject","z":"225a6af5f8bc4cc2","name":"Add List (_ui)","props":[{"p":"_ui","v":"[{\"method\":\"remove\",\"components\":[\"#eltest-upd\"]},{\"method\":\"add\",\"components\":[{\"type\":\"ul\",\"id\":\"eltest-upd\",\"attributes\":{\"name\":\"testy-list\",\"style\":\"list-style: \\\"❌\\\";\"},\"components\":[{\"type\":\"li\",\"id\":\"eltest-upd-1\",\"attributes\":{\"data-row-index\":1,\"class\":\"odd\"},\"slot\":\"1) To do <span name=\\\"when\\\">now</span>\"},{\"type\":\"li\",\"attributes\":{\"data-row-index\":2,\"class\":\"even\",\"id\":\"eltest-upd-2\"},\"slot\":\"2) To do <span name=\\\"when\\\">tomorrow</span>\"},{\"type\":\"li\",\"id\":\"eltest-upd-3\",\"attributes\":{\"data-row-index\":3,\"class\":\"odd\"},\"slot\":\"3) To do <span name=\\\"when\\\">this week</span>\"},{\"type\":\"li\",\"id\":\"eltest-upd-4\",\"attributes\":{\"data-row-index\":4,\"class\":\"even\"},\"slot\":\"4) To do <span name=\\\"when\\\">sometime</span>\"}],\"parent\":\"#more\"}]}]","vt":"json"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":130,"y":280,"wires":[["f3d45472d250833a"]]},{"id":"6b17d81ec2209b1d","type":"inject","z":"225a6af5f8bc4cc2","name":"Ambulance All (_ui)","props":[{"p":"_ui","v":"[{\"method\":\"update\",\"components\":[{\"x-id\":\"eltest-upd\",\"name\":\"testy-list\",\"x-type\":\"ul\",\"x-parent\":\"#more\",\"attributes\":{\"style\":\"list-style: \\\"🚑\\\";\"}}]}]","vt":"json"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":150,"y":560,"wires":[["f3d45472d250833a"]]},{"id":"6b4d8a4a4ca96607","type":"inject","z":"225a6af5f8bc4cc2","name":"Overdue 1 (_ui)","props":[{"p":"_ui","v":"[{\"method\":\"update\",\"components\":[{\"selector\":\"#eltest-upd *[data-row-index=\\\"1\\\"]:not([data-done=\\\"Y\\\"])\",\"attributes\":{\"style\":\"background-color: red; color: yellow; font-weight: bolder;\"}}]}]","vt":"json"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":140,"y":320,"wires":[["f3d45472d250833a"]]},{"id":"c47e58de8dc519b7","type":"inject","z":"225a6af5f8bc4cc2","name":"Tick off 2 (_ui)","props":[{"p":"_ui","v":"[{\"method\":\"update\",\"components\":[{\"selector\":\"#eltest-upd > li:nth-child(2)\",\"# selector\":\"#eltest-upd *[data-row-index=\\\"2\\\"]\",\"# id\":\"eltest-upd-2\",\"attributes\":{\"style\":\"list-style: \\\"✅\\\";\",\"data-done\":\"Y\"}}]}]","vt":"json"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":130,"y":400,"wires":[["f3d45472d250833a"]]},{"id":"7689357d95808fab","type":"inject","z":"225a6af5f8bc4cc2","name":"Tick off 1 (_ui)","props":[{"p":"_ui","v":"[{\"method\":\"update\",\"components\":[{\"selector\":\"#eltest-upd > li:nth-child(1)\",\"# selector\":\"#eltest-upd *[data-row-index=\\\"1\\\"]\",\"# id\":\"eltest-upd-1\",\"attributes\":{\"style\":\"list-style: \\\"✅\\\";\",\"data-done\":\"Y\"}}]}]","vt":"json"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":130,"y":360,"wires":[["f3d45472d250833a"]]},{"id":"cabe1f260b988cc2","type":"inject","z":"225a6af5f8bc4cc2","name":"Un-tick 1 (_ui)","props":[{"p":"_ui","v":"[{\"method\":\"update\",\"components\":[{\"x-id\":\"eltest-upd-1\",\"selector\":\"#eltest-upd > li:nth-child(1)\",\"# selector\":\"#eltest-upd *[data-row-index=\\\"1\\\"]\",\"# id\":\"eltest-upd-2\",\"attributes\":{\"style\":\"list-style: revert;\",\"data-done\":\"N\"}}]}]","vt":"json"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":130,"y":440,"wires":[["f3d45472d250833a"]]},{"id":"56364793494b9db6","type":"inject","z":"225a6af5f8bc4cc2","name":"Chg Due 1 (_ui)","props":[{"p":"_ui","v":"[{\"method\":\"update\",\"components\":[{\"selector\":\"#eltest-upd-1 > [name=\\\"when\\\"]\",\"slot\":\"soon\"}]}]","vt":"json"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":140,"y":480,"wires":[["f3d45472d250833a"]]},{"id":"050cc93892c1d90c","type":"inject","z":"225a6af5f8bc4cc2","name":"Chg Due all (_ui)","props":[{"p":"_ui","v":"[{\"method\":\"update\",\"components\":[{\"selector\":\"#eltest-upd *[name=\\\"when\\\"]\",\"# name\":\"when\",\"slot\":\"soonish\"}]}]","vt":"json"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":140,"y":520,"wires":[["f3d45472d250833a"]]}]