1. props
- The
{{ props.label }}
in my template is binded to my props.props. So the props contain (immutable?) data arriving from the config screen of my ui node. Personally I find it rather confusing to have 2 nested props levels, especially since the upper props level seems nowhere to be used. I assume that is part of the Vue magic...
So, this is perhaps bad attribute naming on my part, but the breakdown is two-fold:
props: {
....
}
On the component definition is a VueJS Options API. props
is a schema to tell anything else in our Vue app what inputs/properties this component needs in order to render. So, for example <my-component prop1="" prop2="" />
Our widget specification is driven by three properties: id
, props
and state
.
id
: The ID given to the node/widget from Node-RED
props
: The object sent by ui-base
as part of the ui-config
, which bundles together the appropriate values from the Node-RED configuration for that node, perhaps config
would have been a better choice of variable names, rather than the double props
, this is something I'm definitely open to changing for easier readability.
state
: This is meant to be providing details on anything overridden at runtime, but I haven't implemented this consistently, entirely my fault.
2. props.state
- Then there is props.state. I thought first that this is some volatile state of my widget, which gets lost (after a refresh?). But I seem to remember that I read somewhere that state on the server side is also used to store the dynamic settings arriving via input messages (which overrule the corresponding settings from my ui node's config screen)? But perhaps I am mistaken. So not sure whether I can store here some of my custom state, without it being overwritten by the dashboard?
My original plan for props.state
was to store dynamic content in here, i.e. visibility, disabled state, etc. but the lines between props
and state
were not clear, as often you can override the props
at runtime, e.g. options
on a ui-dropdown
. The difficulty then came (which I can see you're facing in 5 is that I was duplicating effort client-side of having to constantly check both props
and state
, and it's messy.
As a result, it's become a bit of a mish-mash of values that I really need to clean up and provide consistency on, but with all the new requests, bugs, etc. coming in, and now only working on Dashboard 2 days a week at most, spending a few days just doing technical debt, and ensuring cleaner documentation hasn't been possible.
Server-side, my architecture is a little cleaner, where I also use a store-based architecture, with data
matching the behaviour of the client, i.e. storing message history, and the statestore
(server-side) storing anything that is overridden from the base configuration, so Node-RED maintains the configuration defined at deploy-time, and then statestore
keeps track of anything that has since changed. The two stores are then merged
3. data () { ... }
- Then there is the data section. Not sure for which data this is used.
This is a part of the VueJS Options API to define a Vue Component. data ()
is entirely scoped locally to the Vue component, and defines variables that are used component-wide, i.e. rendered part of the HTML and/or used across JavaScript methods defined on the component too.
4. VueX Stores
- There are also Vuex datastores. Is that for persistent data, or is it the same as the above props in some way? Because it also seems to be used to store state...
vuex is used to persist data across the application in a centralised location, any component can read/write into the stores we have. Within Dashboard 2.0, I have the following stores:
data
: this stores any of the latest or historical messages for each widget/node
ui
: this stores the ui-config
for the whole Dashboard as sent by Node-RED, including th full list of pages
, groups
, themes
and widgets
.
setup
: This is shoe-horned a little, but fundamentally stores the setup object sent on first load, which in core provides the SocketIO configuration, generated server-side. It is also possible to extend this with the Third Party Plugins (and is what we use for the Multi-User Dashboards)
5. Dynamic Properties
- In the above example the props.label is showed in the widget. While I understand that is useful for fixed texts, in my use case I need to be able to change the label afterwards. Does this mean I need to copy in js code my props.label content to somewhere else, and then somehow bind that intermediate variable to my widget? Or perhaps that needs to go into the computed data section?
So, the "cleanest" (I use this phrase in the loosest of terms) example I have for this is ui-dropdown
. When a message is received with .options
inside, server-side we have a beforeSend()
handler, which is before it's sent to the client. This stores, in our server-side statestore
any msg.options
that are found.
Client-side, we then also check for .options
when a new message is received in the custom onInput
function, and store that locally on our component's this.items
.
On refresh, our ui-base
, when building the ui-config
merges the configuration from Node-RED, which would still have the original options
and the statestore
into the widget configuration, so the latest .options
would be provided to the client-side where they would be loaded and shown.
6. OnLoad
- Then there is the data being stored in the input messages, and those messages are also being stored somewhere. Not sure anymore if there is a msg replay mechanism (e.g. at browser refresh) like in the old days?
Each core widget can provide an onLoad
function. When our client first loads a widget, the server-side will pass an on-load
event via SocketIO with the latest msg
it's aware of. So, if you want to load the latest state, provide a listener for onLoad
client-side (for third party widgets - docs are here) which accepts that msg
and does whatever you need to do with it on the client.
7. Data Transfer
- It is also not clear to me how and when the data is transported between the server side and the client side. For example when I save data to the server-side datastore, what happens then?
Data being stored to the statestore
just does exactly that, nothing is communicated to the client unless you explicitly request it to be. Our Events Architecture diagram does cover the foundatinal event structure between Client (in blue) and Node-RED (in red).
Or when a client connects, how it loads his data from my server. While some developers might not need this kind of information, it would help me to find a good mechanism to store and share my state in the SVG node...
In this particular example, you see in the diagram linked above that we fire a widget-load
event for each widget on the screen. The server-side nodes then send a widget-load
event back to the client with the latest msg
stored in the server-side datastore