Well, sometimes you have to do it all wrong and come full circle
I went back to almost what @TotallyInformation has: messages contain property values that are just pushed into the components. I had changed this to a message dispatch where components contain a handler method that is called with the message. I had the linkage using the same ref=
property as @TotallyInformation's examples have.
The reason I went back is that in Vue updating values should happen through properties and through the general "reactivity". Sending messages around or calling handler methods just goes around this and thus ends up clashing. In @TotallyInformation's examples the clash comes from vue complaining that props are being updated directly. Going back to using the reactivity mechanism properly reduced my code size significantly, everything is now so simple.
So what I ended up with is:
- the app main (index.js) contains a
nr
data, which holds all data that has come in from node-red (hence "nr"). - when a message comes in, it must have a topic and a payload, the message is simply stored as
nr[msg.topic] = msg.payload
(technically I have to useVue.set
, but that's insignificant). - the page html instantiates components and for components that need to get data from node-red the appropriate portions of the
nr
data are bound to the component's props using the standard Vuev-bind
And that's it, couldn't be simpler!
simple example
Simple example: a stat component that shows a title, a value, and a units string.
- the component has 3 properties: title, unit, value
- the page html instantiates the component and binds the value for updating like this:
<stat title="bedroom" unit="°F" v-bind:value="nr.bedroom_temperature"></stat>
- the NR flow sends a message to the page to update the temperature like this:
{ topic: "bedroom_temperature", payload: 77 }
- the result:
array example
A more complex example has an array component that expects an array of title/unit/value objects and generates an array of stat components for all those values:
- the array component has some properties, including
array
(in this example there's no other property, but there could be in the future) - the page html instantiates the array component and provides the template for the stat component as follows:
<array v-bind="nr.temperature_array">
<template v-slot:default="slotProps">
<stat v-bind="slotProps"></stat>
</template>
</array>
the v-bind
s used here bind all properties of the component, as opposed to the v-bind:value
used above that only bound the value
property
- the message sent from node-red looks as follows:
{ topic: "temperature_array",
payload: {
array: [
{ title: "bedroom", unit: "°F", value: "75" },
{ title: "living room", unit: "°F", value: "72" },
...,
]}}
In this case, the array
property of the message payload updates the property of the same name in the array component.
- the result:
I uploaded the whole thing I have to GitHub - tve/uibuilder-test: Node-Red Test Dashboard using uibuilder in case someone wants to take a peek...