# How to sync the FULL config between server and client side state

**URL:** <https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252>\
**Category:** Dashboard\
**Tags:** flexdash, dashboard-2\
**Created:** [4 July 2024 05:55 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252 "2024-07-04T05:55:31Z")\
**Posts on this page:** 20\
**Page:** 4

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [17 July 2024 19:50 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/61 "2024-07-17T19:50:31Z")

</div>

> [@BartButenaers](#):
>
> When an input message is injected, you update the State store. But how does these State store changes arrive in your Vue frontend?

The message goes to the frontend and then, basically, I repeat the code that is in the server to update the state in the client. So in `processMsg()` I have, for example,

```auto
            if ("enabled" in msg) {
                // update our local copy of props
                this.props.enabled = msg.enabled
            }

```

I have been thinking about how to avoid that. When the widget is mounted the server sends the `props` object to the client. The `props` object is effectively the state store and node config merged . One option would be to attach that to each message sent to the client. Do you know whether `props` is available via some API? If so it would be easy to add it into the message as `msg._props`. I don't know if there is any down side to doing this other than bandwidth. In fact it would only be necessary to include overridden properties and data in the state store.

> [@BartButenaers](#):
>
> You don't send your message to the next nodes in the flow. Does this mean there is no passthrough of input messages possible?

Correct, I virtually never use pass through. If ever it is needed it is easy just to wire round the node and achieve the same thing.

> [@BartButenaers](#):
>
> You watch a `value` in your frontend. How does this work for you?

`value` is updated by vue when the user makes a selection in the dropdown, via `v-model="value"` in the `v-select`. So the watch triggers when the user makes a selection. The complication is that if the selection is changed by an incoming message then that is also picked up by the watch, so I have to use the rather clunky technique of using flags `this.fromManual` and `this.valueFromMsg` to track where the change originated. I need to revisit that as I feel it shouldn't need two flags, but at the time it did seem necessary. If I do need two then at least the naming should be consistent.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [17 July 2024 20:08 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/62 "2024-07-17T20:08:44Z")

</div>

> [@Colin](#):
>
> One option would be to attach that to each message sent to the client

That might be useful for simple widgets with only a small amount of state. But if I have an svg floorplan visualizing a large serie of sensors, I cannot afford to send the entire state (incl the static static from my config screen) to the clients every time. I am now looking for an easy way to determine the delta and send that to the clients. Of course a single input message will result in multiple changes to the state store, and I would like to send all these changes as a single event/transaction/batch to the clients.

And afterwards replay that delta on the client side state. Because like you say it is not convenient if you have to write the same code twice, once for the server side and once for the client side.

No idea whether e.g. Vue offers something out of the box, or that I need to implement it myself.

> [@Colin](#):
>
> Correct, I virtually never use pass through

Hmm I would like my ui nodes to behave similar to the core nodes, for features like e.g. passthrough of messages. Therefore I am not tempted to manipulate the input messages, in order to be send my state store delta's to the clients. I just want to copy data from my input message to the state store, and then have a separate event to push the state-change to the clients via the socket. That way my input messages are untouched, and can optionally be passed through the output.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [17 July 2024 20:25 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/63 "2024-07-17T20:25:38Z")

</div>

> [@BartButenaers](#):
>
> if I have an svg floorplan visualizing a large serie of sensors, I cannot afford to send the entire state

Good point.

> [@BartButenaers](#):
>
> I would like my ui nodes to behave similar to the core nodes, for features like e.g. passthrough of messages. Therefore I am not tempted to manipulate the input messages, in order to be send my state store delta's to the clients.

You could call `send(msg)` to send it on before you add in your delta definition. In fact it might be necessary to clone it before calling send().  
Alternatively I think you could use a custom event to send it separately from the message, but I don't know exactly how to do that.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [17 July 2024 20:26 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/64 "2024-07-17T20:26:51Z")

</div>

> [@BartButenaers](#):
>
> I would like my ui nodes to behave similar to the core nodes, for features like e.g. passthrough of messages.

Can you envisage cases with the svg node where passthrough is actually useful?

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [17 July 2024 20:30 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/65 "2024-07-17T20:30:52Z")

</div>

> [@Colin](#):
>
> Can you envisage cases with the svg node where passthrough is actually useful?

Good point!  
Honest answer: No.  
But: I am pretty sure that after a month some users will popup to ask for this feature 😉

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [17 July 2024 20:37 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/66 "2024-07-17T20:37:22Z")

</div>

> [@BartButenaers](#):
>
> But: I am pretty sure that after a month some users will popup to ask for this feature

Tell them to wire round the node. Pass round rather than pass through. I can't see any point adding complexity to the code and the ui for a feature of very little or no use. There have been many instances here where passthrough has caused problems, particularly infinite loops.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [17 July 2024 20:54 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/67 "2024-07-17T20:54:21Z")

</div>

> [@Colin](#):
>
> Pass round rather than pass through

For my svg node it might be not much of a use perhaps. However perhaps it is useful for my other ui nodes. Moreover the passthrough feature is a [standard feature](https://github.com/FlowFuse/node-red-dashboard/blob/main/nodes/config/ui_base.js#L976) in the dashboard (and most core ui nodes), so I want the state store syncing mechanism also to support it. And I can't do that when I start manipulating input messages.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [18 July 2024 07:46 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/68 "2024-07-18T07:46:37Z")

</div>

This works in onInput to passthrough the incoming message then build the deltas data and pass that to the client.

```auto
                // passthrough incoming message
                send(RED.util.cloneMessage(msg))
                // build config delta
                msg._propsDelta = ...

```

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [19 July 2024 12:33 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/69 "2024-07-19T12:33:49Z")

</div>

> [@Colin](#):
>
> Alternatively I think you could use a custom event to send it separately from the message, but I don't know exactly how to do that.

If I understood the question correctly - you can define a custom event handler in the server node, which will reflect the msg to all client widgets.

```auto
// Msgs from the client
['clientMsgs'+node.id]: function (conn, id, msg) {
	switch (msg.msgType)
	{
		case 'userEditSync':
			// save the update in the datastore
			// base.stores.data.save(...);

            // update all other client widgets, by having the node send the msg to itself,
            // forcing replication to all
			node.emit('input', msg); // 
			break;
      .....

```

you can have the client embed its `_client` identifier in the msg, so that it can ignore that msg once it loops back to itself

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [19 July 2024 12:57 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/70 "2024-07-19T12:57:20Z")

</div>

That is not quite the requirement, it is to have a message from the server sent to all clients (subject to \_client), but it is to happen in the onInput event prior to the message itself being sent.

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [19 July 2024 21:27 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/71 "2024-07-19T21:27:47Z")

</div>

Not sure I understood the requirement. You want to receive a message in the server node, and within `onInput` create & broadcast another message to all clients, before the original message is sent?

As far as I checked, `onInput` enables you to read/change the incoming msg **before** sending it to the clients. So you can just enrich the original msg with any new data you want.

If you want the new data to be sent in a separate msg before the original msg, then until @joepavitt gives us proper server node APIs for input handling and client broadcasting, you can use the following workaround (ugly but works).

1. Receive the incoming msg ("msg-1") in `onInput`
2. Set some "ignoreMe" flag on msg-1
3. Create your new message (msg-2)
4. Send msg-2 to your node's own input port: `node.emit('input', msg-2)`
5. If the original message is required, clone the original msg-1 to msg-3, and send it as well

Once you exit `onInput`, messages 1, 2, 3 will be broadcasted in this order to the clients. The clients should reject msg-1 per the "ignoreMe" flag.  
You will also need to flag msg 2 & 3 so that they don't get reprocessed on the server node (endless loop).

---

<div class="post-metadata">

**Author:** ![HaroldPetersInskipp](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/haroldpetersinskipp/32/42319_2.png) [@HaroldPetersInskipp](https://discourse.nodered.org/u/HaroldPetersInskipp)\
**Post date:** [19 July 2024 21:51 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/72 "2024-07-19T21:51:51Z")

</div>

My solution to the problem in the old AngularJs dashboard was to store all the needed variables as flow context, then create a function that has only `return {payload:""}` connect that to a change node that pulls all the flow variables needed for the full state into `msg.payload` and connect that to my dashboard ui\_template node so it could only receive messages with the full state no matter the incoming message. I also put a ui\_control node before the function to set the full state when any event is triggered.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [20 July 2024 07:33 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/73 "2024-07-20T07:33:09Z")

</div>

> [@omrid](#):
>
> As far as I checked, `onInput` enables you to read/change the incoming msg **before** sending it to the clients. So you can just enrich the original msg with any new data you want.

Yes, that works, but the result is that it pollutes the message passed on if message passthrough is enabled. In practice this is unlikely to be a problem, but it is undesirable. To avoid that, the message can be cloned and the cloned message passed through to other nodes, then the original message can have the additional data added to it and sent to the clients. It works but again seems messy.

The example node has in the server code

```auto
            onSocket: {
                /*
                'my-custom-event': function (conn, id, msg) {
                    console.info('"my-custom-event" received:', conn.id, id, msg)
                    console.info('conn.id:', conn.id)
                    console.info('id:', id)
                    console.info('msg:', msg)
                    console.info('node.id:', node.id)
                    // emit a msg in Node-RED from this node
                    node.send(msg)
                }
                */
            }

```

Which shows how to listen on a custom event. Can I not send a custom event from the server and listen for it in the clients?

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [20 July 2024 07:34 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/74 "2024-07-20T07:34:51Z")

</div>

> [@HaroldPetersInskipp](#):
>
> My solution to the problem in the old AngularJs dashboard was to store all the needed variables as flow context,

We are talking here about a custom node, not a ui-template, so the user should not have to add anything to his flows to achieve the result.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [20 July 2024 15:27 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/75 "2024-07-20T15:27:13Z")

</div>

Another reason for sending the data separate from the message is that it may contain information that must not be replayed on page refresh.

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [21 July 2024 07:46 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/76 "2024-07-21T07:46:44Z")

</div>

> [@Colin](#):
>
> Can I not send a custom event from the server and listen for it in the clients?

I assume you could add a dedicated listener on the client node, something like

```auto
    mounted () {
		// set msg listener
        this.$socket.on('my-new-listener:' + this.id, (msg) => {
			...

```

However, in the server node, you will need to know the socket & client Ids, which AFAIK are not exposed to us at the server node.

But I see no issue with using `node.emit('input',msg)`, telling the server node to broadcast the msg like any other incoming flow msg. You just need to ignore this self-sent msg when it goes through your server node's `onInput`

One thing to bear in mind here, is that the msg is submitted to the server node's input queue and sent asynchronously, i.e. if there are other messages already in the queue, your new message will be sent after them.

.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [21 July 2024 08:59 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/77 "2024-07-21T08:59:35Z")

</div>

> [@omrid](#):
>
> I assume you could add a dedicated listener on the client node

> [@omrid](#):
>
> However, in the server node, you will need to know the socket & client Ids,

Good point, I had neglected to consider the fact that the message must only be sent to the clients showing the node.

> [@omrid](#):
>
> I see no issue with using `node.emit('input',msg)`, telling the server node to broadcast the msg like any other incoming flow msg. You just need to ignore this self-sent msg when it goes through your server node's `onInput`

That does work, in fact it is rather easier than I had thought, as node.emit appears not to add a message to the servers input queue, but to directly call onInput. So it is not necessary to worry about messages already in the server queue, and also a message sent using node.emit is sent to the client _before_ the original message. So this appears to work, in the js file:

```auto
            onInput: function (msg, send, done) {
                // ignore this if msg._updates present so that it gets sent directly to the clients
                if (msg._updates) {
                    return
                }
                // process msg as necessary
                // send the updates back to onInput for sending to the clients
                node.emit('input', {_updates: {/*update data*/} )
                // return so that the original msg is sent to clients
                return
            }

```

Thanks for suggesting this, which will do what I need for the moment. It is messy, however, what is needed, I think, is an API to allow sending to the clients. I will raise a feature request for this.

@BartButenaers I think this technique should allow updates be sent to the clients in a form that minimises the requirement for duplicated code in the server and in the client. I am going to try and implement it in my dropdown node.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [21 July 2024 09:14 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/78 "2024-07-21T09:14:36Z")

</div>

I have submitted a feature request to add API methods to allow data passing between client and server side of the node. [Add API to allow third party ui nodes to pass data between server and client code · Issue #1116 · FlowFuse/node-red-dashboard · GitHub](https://github.com/FlowFuse/node-red-dashboard/issues/1116)

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [21 July 2024 10:18 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/79 "2024-07-21T10:18:59Z")

</div>

> [@Colin](#):
>
> minimises the requirement for duplicated code in the server and in the client

Hi @Colin,  
Could you please explain how we can avoid duplicating code on client and server this way? You are still forwarding messages to the client, which contain only partial state, or am I mistaken? I would think we need to update the server side state, and that the dashboard framework makes sure our client side state is updated, without every ui node developer having to do it himself...

I have to admit that I currently lost a bit the Node-RED fun factor. Because beside a few partial migrated ui nodes, I got nowhere last year. Turning round and round in circles.... So not following Discourse in depth anymore at the moment. Hopefully the fun comes back soon...

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [21 July 2024 12:43 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/80 "2024-07-21T12:43:33Z")

</div>

> [@BartButenaers](#):
>
> the dashboard framework makes sure our client side state is updated, without every ui node developer having to do it himself

I am not sure that is practically possible, but that may be because my imagination is not up to it. The server cannot know the state of all attached clients. I am hoping the technique I am thinking of will end up with a handful of lines of code at each end.

> [@BartButenaers](#):
>
> explain how we can avoid duplicating code on client and server this way?

I am going to try and implement it in my dropdown node and see how it works out in practice.

[Previous page](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252.md?page=3)

[Next page](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252.md?page=5)
