# How to retain the state of a button on and off between page updates and different browsers?

**URL:** <https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404>\
**Category:** Dashboard\
**Tags:** dashboard-2\
**Created:** [13 March 2024 16:50 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404 "2024-03-13T16:50:20Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![diegodamaceno](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/diegodamaceno/32/85742_2.png) [@diegodamaceno](https://discourse.nodered.org/u/diegodamaceno)\
**Post date:** [13 March 2024 16:50 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/1 "2024-03-13T16:50:20Z")

</div>

@joepavitt

I would like to understand and form a consistent variable that can be retrieved on page updates and across different browsers. I currently use the code below, but I'm not sure how to retrieve the states. Anyone who can help I would appreciate it.

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/9/2933a95d370d7d02da9a9cd5a01e48329634b466.png)

```auto
<template>
    <v-btn class="button_fita_cozinha" ref="button" stacked @click="alternar">
        <div class="title_fita_cozinha">Cozinha</div>
        <v-icon class="icon_fita_cozinha" ref="icon">{{icon}}</v-icon>
    </v-btn>
</template>

<script>
    export default {
        data() {
            return {
                value: "OFF",
                icon: "mdi-led-strip-variant"
            };
        },
        methods: {
            alternar: function () {
                if (this.value === 'ON') {
                    this.desligar();
                } else if (this.value === 'OFF') {
                    this.ligar();
                } else {
                    this.desligar();
                }
            },
            ligar: function () {
                this.icon = "mdi-led-strip-variant";
                this.$refs.icon.$el.style.color = '#BD9608';
                this.$refs.icon.$el.style.textShadow = '0px 0px 10px #BD9608';
                if (this.value === 'OFF') {
                    this.send({ payload: 'ON' });
                    this.value = "ON"; 
                }
            },
            desligar: function () {
                this.icon = "mdi-led-strip-variant";
                this.$refs.icon.$el.style.color = '#A9A9A9';
                this.$refs.icon.$el.style.textShadow = '0px 0px 0px';
                if (this.value === 'ON') {
                    this.send({ payload: 'OFF' });
                    this.value = "OFF"; 
                }
            }
        },
        watch: {
            msg: function(){
                if(this.msg.payload != undefined){
                    console.log('got message :',this.msg)
                    if (this.msg.payload === "ON") {
                        this.ligar();
                    } else if (this.msg.payload === "OFF") {
                        this.desligar();                        
                    }
                }
            }
        }
    }
</script>

<style>
    .button_fita_cozinha {
        display: flex; 
        flex-direction: column; 
        margin: auto; 
        height: 75px; 
        width: 75px; 
        background-color: #4F4F4F; 
        color: #000000; 
        border: 1px solid #000000; 
        ont-size: 14px; 
        border-radius: 18px;"
    }
    .title_fita_cozinha {
        font-size: 75%;
    }
    .icon_fita_cozinha {
        font-size: 40px;
    }
</style>

```

---

<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:** [13 March 2024 17:33 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/2 "2024-03-13T17:33:45Z")

</div>

My solution to a similar problem was to ensure that every message sent to the template, or sent from the template, includes all the state information (in a property, msg.state for example). Then when the dashboard is opened in a new browser, or the page is refreshed, the last message sent to or sent from the template will be sent to it so it knows the current state.

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [13 March 2024 18:48 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/3 "2024-03-13T18:48:00Z")

</div>

I recently updated the Events Architecture documentation to assist with understanding in this space, in particular, the ["Dashboard Actions" Events Flow](https://dashboard.flowfuse.com/contributing/guides/events.html#dashboard-actions-event-flow).

This is the important (new) diagram:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/3/5/35f90fe6ff45717c5a615ef250c2129e5616ea9b.jpeg)

What it shows is the difference between the client actions, when you run `send()` in a `ui-template`, that fires the `widget-send` event, which does store any payload/msg you send into the server-side store for that widget.

In turn, what that means is, given our ["Loading Event Flow"](https://dashboard.flowfuse.com/contributing/guides/events.html#loading-event-flow), we can see that this retrieves the latest `msg` stored against a widget/`ui-template`:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/c/7/c785e494606e276c52dfe97abab981646d8ee3db.jpeg)

The widget itself will automatically populate the client-side `msg` object when the `ui-template` first loads, with whatever data is stored in the server-side data store (i.e. the last thing sent via `send()`), and so your `watch` on `msg` is a feasible approach here as that will catch on first load. The disadvantage of this approach is that it will run that for all incoming messages too, which also modify `msg`.

The other option, which I haven't actually exposed too much in the docs because the state is auto-loaded into `msg`, but does work (I've just tested, and I'll update docs accordingly):

```js
this.$socket.on('widget-load:'+this.id, (msg) => {
   // do stuff with the loaded msg
})

```

Which will _only_ run when the widget is first loaded, and if there is a `msg` to load. It does not fire when there is no data stored in the server-side store for a widget.

FYI @hotNipi as I know this will be useful for you too, potentially even @BartButenaers too

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [13 March 2024 18:53 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/4 "2024-03-13T18:53:08Z")

</div>

Just to provide an example too:

```js
<template>
  <div>Last Loaded Message {{ loaded }}:</div>
  <pre>{{lastMsg}}</pre>
  <div>
    <v-text-field v-model="payload" label="Payload"></v-text-field>
    <v-btn @click="send({payload})">Save Payload</v-btn>
  </div>
</template>
<script>
  export default {
    data () {
        return {
          loaded: false,
          lastMsg: null,
          payload: ''
        }
    },
    mounted () {
      console.log('mounted', this.id)
      this.$socket.on('widget-load:' + this.id, (msg) => {
        this.loaded = true
        this.lastMsg = msg
      })
    }
  }
</script>

```

---

<div class="post-metadata">

**Author:** ![krambriw](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/krambriw/32/5429_2.png) [@krambriw](https://discourse.nodered.org/u/krambriw)\
**Post date:** [13 March 2024 19:03 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/5 "2024-03-13T19:03:32Z")

</div>

@Colin  
Similar concept I have used for years in my html based hack; when the browser is opened and initiates the web socket connection, a status request is sent to Node-RED that responds with all known statuses in a number of messages. For dashboard v1 I use "theScope" instead

The response messages to the request are received by all connected browser clients so they all get synchronized as well (regardless if it is needed or not)

---

<div class="post-metadata">

**Author:** ![diegodamaceno](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/diegodamaceno/32/85742_2.png) [@diegodamaceno](https://discourse.nodered.org/u/diegodamaceno)\
**Post date:** [13 March 2024 20:27 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/6 "2024-03-13T20:27:20Z")

</div>

So would this be the correct assembly idea to save the status between browsers and when reloading?

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/9/7/97834eee4875f7b20dc84d24a4d46094aba773d2.png)

```auto
<template>    
    <div class="contaner_ar_condicionado">
        <div class="title_ar_condicionado">Ar Condicionado</div>
        <div class="buttons_ar_condicionado">
            <v-btn class="button_ar_condicionado" @click="mais">        
                <v-icon class="icon_ar_condicionado">mdi-plus-thick</v-icon>
            </v-btn>
            <v-btn class="button_ar_condicionado" @click="alternar">
                <v-icon class="icon_ar_condicionado" ref="icon">mdi-power</v-icon>
            </v-btn>
            <v-btn class="button_ar_condicionado" @click="menos">
                <v-icon class="icon_ar_condicionado">mdi-minus</v-icon>
            </v-btn>
        </div>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                value: ''
            };
        },
        mounted() {            
            this.$socket.on('widget-load:' + this.id, (msg) => {
                this.value = msg.payload;
                if (this.value === "ON") {
                    this.on();
                } else {
                    this.off();
                }
            });
        },
        methods: {
            alternar() {
                if (this.value === 'ON') {
                    this.off();
                    this.value = "OFF";
                    this.send({ payload: 'OFF' });
                } else {
                    this.on();
                    this.value = "ON";
                    this.send({ payload: 'ON' });
                }
            },
            mais() {
                if (this.value === 'ON') {                    
                    this.send({ payload: 'MAIS' });
                }                
            },
            menos() {
                if (this.value === 'ON') {                    
                    this.send({ payload: 'MENOS' });
                } 
            },
            on() {
                this.$refs.icon.$el.style.color = '#BD9608';
                this.$refs.icon.$el.style.textShadow = '0px 0px 10px #BD9608';                             
            },
            off() {
                this.$refs.icon.$el.style.color = '#A9A9A9';
                this.$refs.icon.$el.style.textShadow = '0px 0px 0px';
            }
        }
    }
</script>

<style>
    .contaner_ar_condicionado {
        display: flex; 
        justify-content: center;
        align-items: center; 
        flex-direction: column; 
        height: 75px; 
        width: 210px; 
        background-color: #4F4F4F; 
        border: 1px solid #000000; 
        border-radius: 18px;
    }
    .buttons_ar_condicionado {
        display: flex; 
        justify-content: center;
        align-items: center; 
        flex-direction: row;         
    }
    .button_ar_condicionado {
        display: flex; 
        justify-content: center; 
        align-items: center;        
        background-color: transparent;
    }
    .title_ar_condicionado {
        font-size: 14px;
    }
    .icon_ar_condicionado {
        font-size: 30px; 
    }
</style>

```

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [14 March 2024 11:50 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/7 "2024-03-14T11:50:12Z")

</div>

That looks good to me

---

<div class="post-metadata">

**Author:** ![diegodamaceno](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/diegodamaceno/32/85742_2.png) [@diegodamaceno](https://discourse.nodered.org/u/diegodamaceno)\
**Post date:** [14 March 2024 13:37 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/8 "2024-03-14T13:37:38Z")

</div>

I'm applying this concept to all my material, but I still have a challenge. There are 2 panels open, when the button is toggled in one, this change does not appear instantly in the other. Whenever I toggle one button, I need to refresh the page on the other to get the new status.

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/4/24277c8fac2ae79ff143654bcf5fa67e84cec474.png)

```auto
<template>
    <v-btn class="button_Quarto" stacked @click="alternar">
        <div class="title_Quarto">Quarto</div>
        <v-icon class="icon_Quarto" ref="icon">mdi-bed</v-icon>
    </v-btn>
</template>

<script>
    export default {
        data() {
            return {
                value: ''
            };
        },
        mounted() {            
            this.$socket.on('widget-load:' + this.id, (msg) => {
                this.value = msg.payload;
                if (this.value === "ON") {
                    this.on();
                } else {
                    this.off();
                }
            });
        },
        methods: {
            alternar() {
                if (this.value === 'ON') {
                    this.off();
                    this.value = "OFF";
                    this.send({ payload: 'OFF' });
                } else {
                    this.on();
                    this.value = "ON";
                    this.send({ payload: 'ON' });
                }
            },
            on() {
                this.$refs.icon.$el.style.color = '#BD9608';
                this.$refs.icon.$el.style.textShadow = '0px 0px 10px #BD9608';                             
            },
            off() {
                this.$refs.icon.$el.style.color = '#A9A9A9';
                this.$refs.icon.$el.style.textShadow = '0px 0px 0px';
            }
        },
        watch: {
            msg: function() {
                if (this.msg.payload === "ON") {
                    this.on();
                    this.send({ payload: 'ON' });
                } else {
                    this.off();
                    this.send({ payload: 'OFF' });
                }                        
            }
        }
    }
</script>

<style>
    .button_Quarto {
        display: flex; 
        flex-direction: column; 
        margin: auto; 
        height: 75px; 
        width: 75px; 
        background-color: #4F4F4F; 
        color: #000000; 
        border: 1px solid #000000; 
        font-size: 14px; 
        border-radius: 18px;"
    }
    .title_Quarto {
        font-size: 85%;
    }
    .icon_Quarto {
        font-size: 40px;
    }
</style>

```

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [14 March 2024 13:42 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/9 "2024-03-14T13:42:29Z")

</div>

> [@diegodamaceno](#):
>
> Whenever I toggle one button, I need to refresh the page on the other to get the new status.

This is actually a bug in the underlying Dashboard 2.0 architecture at the moment that @Colin had recently flagged to me. I need to re-visit the events architecture and workout a solution here.

---

<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:** [14 March 2024 14:07 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/10 "2024-03-14T14:07:05Z")

</div>

> [@joepavitt](#):
>
> This is actually a bug in the underlying Dashboard 2.0 architecture at the moment

I don't think that applies when using the ui-template does it? That was about core nodes, though I can't find an open issue about it.

@diegodamaceno the solution is to send the new state information back and into the template again so the other instances get updated. Make sure you don't end up in an infinite loop obviously.

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [14 March 2024 14:18 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/11 "2024-03-14T14:18:25Z")

</div>

Your original point was about core nodes, but the same infrastructure is in place for the underlying `ui-template`, and so they are related.

I've captured an issue here: [Clients get out of sync from centralised datastore · Issue #679 · FlowFuse/node-red-dashboard · GitHub](https://github.com/FlowFuse/node-red-dashboard/issues/679)

---

<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:** [14 March 2024 14:43 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/12 "2024-03-14T14:43:46Z")

</div>

> [@joepavitt](#):
>
> the same infrastructure is in place for the underlying `ui-template`

How would this work with a ui-template?

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [14 March 2024 14:56 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/13 "2024-03-14T14:56:05Z")

</div>

That's partly what I need to work out 😃

---

<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:** [14 March 2024 14:57 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/14 "2024-03-14T14:57:06Z")

</div>

OK, I will await your deliberations with eager anticipation 🙂

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [13 April 2024 14:57 UTC](https://discourse.nodered.org/t/how-to-retain-the-state-of-a-button-on-and-off-between-page-updates-and-different-browsers/86404/15 "2024-04-13T14:57:44Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
