Help needed: Dashboard 2 & Vue -> reset values on refresh

Hello everyone,

I'm currently experimentin g with DB2 & VUE designs to generate new UI components for my NR environment.

This is my aproach for a Light Switch which is

  • triggered by ON/OFF command at any time
  • triggered by motion during specific periods (DAY,NIGHT,TWILIGHT,etc)
  • the light will stay ON for a given duration (any motion will reset the timer)
  • the brightness can be adjusted

Above pic is showing a custom state, unfortunattly all custom states are returning to default after a page refresh (f5 in browser)

How can the reset to default be avoided .. I have this issue with alll VUE components using the ui-template.

See code here

[
    {
        "id": "6a974f23938f8edf",
        "type": "inject",
        "z": "b9b23c2bc52ffcbb",
        "name": "on",
        "props": [
            {
                "p": "payload.slider1",
                "v": "120",
                "vt": "str"
            },
            {
                "p": "payload.slider2",
                "v": "85",
                "vt": "str"
            },
            {
                "p": "payload.slider3",
                "v": "90",
                "vt": "str"
            },
            {
                "p": "payload.mode",
                "v": "DARK",
                "vt": "str"
            },
            {
                "p": "payload.state",
                "v": "true",
                "vt": "bool"
            },
            {
                "p": "payload.pos",
                "v": "34",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "x": 770,
        "y": 800,
        "wires": [
            [
                "363a684a0601c33f"
            ]
        ]
    },
    {
        "id": "363a684a0601c33f",
        "type": "ui-template",
        "z": "b9b23c2bc52ffcbb",
        "group": "2382a9605dfed38a",
        "name": "new light",
        "order": 3,
        "width": "0",
        "height": "0",
        "head": "",
        "format": "<template>\n  <v-card class=\"mx-auto\" width=\"100%\" color=\"grey\">\n    <template v-slot:title>\n      <v-card-title class=\"text-white font-weight-bold\" v-text=\"mylabel\"></v-card-title>\n      <v-card-subtitle class=\"text-white font-weight-bold\" v-text=\"mysub\"></v-card-subtitle>\n    </template>\n\n    <template v-slot:prepend>\n      <v-btn :icon=\"myicon\" :color=\"mystate_color\" @click=\"myupdate()\"></v-btn>\n    </template>\n\n    <template v-slot:append>\n      <v-btn-toggle v-model=\"mymode\" color=\"blue\" variant=\"elevated\" mandatory divided >\n        <v-btn icon=\"mdi-lightbulb-off-outline\" value=\"OFF\"></v-btn>\n        <v-btn icon=\"mdi-weather-sunny\" value=\"DAY\"></v-btn>\n        <v-btn icon=\"mdi-weather-sunset-down\" value=\"TWILIGHT\"></v-btn>\n        <v-btn icon=\"mdi-weather-night\" value=\"DARK\"></v-btn>\n        <v-btn icon=\"mdi-sleep\" value=\"SLEEP\"></v-btn>\n        <v-btn text=\"LUX\" value=\"LUX\"></v-btn>\n      </v-btn-toggle>\n    </template>\n\n    <v-progress-linear class=\"ma-2\" color=\"primary\" height=\"20\" :model-value=\"slider\" bg-opacity=\"0.6\" rounded>\n      <template v-slot:default=\"{ value }\">\n        <strong>{{mystate}} - {{mypos}}min / {{myduration}}min</strong>\n      </template>\n    </v-progress-linear>\n\n    <v-slider class=\"my-0\" v-model=\"slider1\" density=\"compact\" :max=\"mymax1\" :step=\"mystep1\" :label=\"mylabel1\"\n      color=\"purple\" :prepend-icon=\"myicon\" hide-details>\n      <template v-slot:append>\n        <v-text-field class=\"my-0\" v-model=\"slider1\" density=\"compact\" style=\"width: 80px\" type=\"number\"\n          variant=\"filled\" hide-details>\n        </v-text-field>\n      </template>\n    </v-slider>\n\n    <v-slider class=\"my-0\" v-model=\"slider2\" density=\"compact\" :max=\"mymax2\" :step=\"mystep2\" :label=\"mylabel2\"\n      color=\"purple\" :prepend-icon=\"myicon\" hide-details>\n      <template v-slot:append>\n        <v-text-field class=\"my-0\" v-model=\"slider2\" density=\"compact\" style=\"width: 80px\" type=\"number\"\n          variant=\"filled\" hide-details>\n        </v-text-field>\n      </template>\n    </v-slider>\n\n    <v-slider class=\"my-0\" v-model=\"slider3\" density=\"compact\" :max=\"mymax3\" :step=\"mystep3\" :label=\"mylabel3\"\n      color=\"purple\" :prepend-icon=\"myicon\" hide-details>\n      <template v-slot:append>\n        <v-text-field class=\"my-0\" v-model=\"slider3\" density=\"compact\" style=\"width: 80px\" type=\"number\"\n          variant=\"filled\" hide-details>\n        </v-text-field>\n      </template>\n    </v-slider>\n    \n  </v-card>\n</template>\n\n<script>\n  export default {\n    data: () => ({\n      myicon: 'mdi-lightbulb-on',\n      mylabel: 'Bedroom Light',\n      mylabel1: 'Timer [min]',\n      mylabel2: 'Brightness [%]',\n      mylabel3: 'min Lux {lux]',\n      slider: 0,\n      slider1: 0,\n      slider2: 0,\n      slider3: 0,\n\n      mymax: 180,\n      mymax1: 180,\n      mymax2: 100,\n      mymax3: 1000,\n\n      mystep: 10,\n      mystep1: 10,\n      mystep2: 10,\n      mystep3: 10,\n\n      mysub: 'motion mode',\n      mypos: '5',\n      myprogress: '70',\n      mystate: true,\n      mystate_color: 'blue',\n      myduration: '20',\n\n      myunit: 'mm',\n      mymode: 'OFF',\n      mydisabled: false,\n      toggle: null,\n      old_msg: null,\n    }),\n\n    watch: {\n      // watch for any changes of \"count\"\n  \n      msg: function () \n      {\n        if (this.msg.payload.slider1 != undefined) this.slider1=this.msg.payload.slider1;\n        if (this.msg.payload.slider2 != undefined) this.slider2=this.msg.payload.slider2;\n        if (this.msg.payload.slider3 != undefined) this.slider3=this.msg.payload.slider3;\n        \n        if (this.msg.payload.mode != undefined)  this.mymode=this.msg.payload.mode;\n        if (this.msg.payload.state != undefined) this.mystate=this.msg.payload.state;\n\n        if (this.msg.payload.pos != undefined) this.mypos=this.msg.payload.pos;\n\n\n        //this.send(this.msg);\n\n      },\n      mystate: function () {\n        if (this.mystate ==true) \n        {\n          this.mystate_color=\"blue\";\n        }\n        else\n        {\n          this.mystate_color=\"white\";\n        }\n\n      this.msg.payload=this.mystate;\n      this.msg.topic=\"CMD\";\n      this.send(this.msg)\n      },\n\n      mymode: function () {\n      this.msg.payload=this.mymode;\n      this.msg.topic=\"MODE\";\n      this.send(this.msg)\n      },\n\n      slider1: function () {\n      this.myduration=this.slider1;\n      this.slider=this.mypos/this.myduration*100;\n\n      this.msg.payload=this.slider1;\n      this.msg.topic=\"TIMER\";\n      this.send(this.msg)\n      },\n\n      slider2: function () {\n      this.msg.payload=this.slider2;\n      this.msg.topic=\"LEVEL\";\n      this.send(this.msg)\n      },\n\n      slider3: function () {\n      this.msg.payload=this.slider3;\n      this.msg.topic=\"minLUX\";\n      send.this(this.msg)\n      },\n\n    },\n    computed: {\n    // automatically compute this variable\n    // whenever VueJS deems appropriate\n    },\n    methods: {\n    // expose a method to our <template> and Vue Application\n            myupdate()\n            {        \n              if (this.mystate ==true)\n              {\n                this.mystate=false;\n              }\n              else\n              {\n                this.mystate=true;\n              }\n            }\n      },\n    mounted() {\n      // code here when the component is first loaded\n      },\n    unmounted() {\n      // code here when the component is removed from the Dashboard\n      // i.e. when the user navigates away from the page\n      }\n  \n  }\n</script>",
        "storeOutMessages": true,
        "passthru": false,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 920,
        "y": 820,
        "wires": [
            [
                "5ce8f56d6f1df0c7"
            ]
        ]
    },
    {
        "id": "62cdb1c94ddfcfe5",
        "type": "inject",
        "z": "b9b23c2bc52ffcbb",
        "name": "off",
        "props": [
            {
                "p": "payload.state",
                "v": "false",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 770,
        "y": 840,
        "wires": [
            [
                "363a684a0601c33f"
            ]
        ]
    },
    {
        "id": "5ce8f56d6f1df0c7",
        "type": "debug",
        "z": "b9b23c2bc52ffcbb",
        "name": "light out",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 1060,
        "y": 820,
        "wires": []
    },
    {
        "id": "2382a9605dfed38a",
        "type": "ui-group",
        "name": "Testing",
        "page": "d03f698ab46f8b85",
        "width": "6",
        "height": "1",
        "order": 2,
        "showTitle": true,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "d03f698ab46f8b85",
        "type": "ui-page",
        "name": "Overview",
        "ui": "a0ddd2d7af1545fc",
        "path": "/Main",
        "icon": "home",
        "layout": "grid",
        "theme": "f286855bd0ef7af5",
        "order": 1,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "a0ddd2d7af1545fc",
        "type": "ui-base",
        "name": "DB2",
        "path": "/dashboard",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-notification",
            "ui-control"
        ],
        "showPathInSidebar": false,
        "navigationStyle": "default"
    },
    {
        "id": "f286855bd0ef7af5",
        "type": "ui-theme",
        "name": "Default Theme",
        "colors": {
            "surface": "#404040",
            "primary": "#0094ce",
            "bgPage": "#000000",
            "groupBg": "#c3c1c1",
            "groupOutline": "#f8baba"
        },
        "sizes": {
            "pagePadding": "12px",
            "groupGap": "12px",
            "groupBorderRadius": "4px",
            "widgetGap": "12px"
        }
    }
]

Thank you for any help (sorry I posted a similar thread before)

thx for any help

Yes, and never replied to my final request there.

What I said there still stands, add this to your watch, msg function

console.log(`Message received: ${JSON.stringify(this.msg)}`)

Open the developer console in your browser, make sure you are looking at the Console tab.
Refresh the page then send a message to the template and you should see it in the console. Now refresh and you should see that the dashboard resends the last message sent to or sent from the template.

Also you will see in the console that you have an error in your slider3 function. Though I don't think this is related to the problem.

the console is not really showing anyting in regards how/wht the sliders and others have been set
back to the initial state :frowning:

Post the flow with the log statement included and I will give it a go. That is what I asked on your last thread but you never posted it.

Did you fix the slider3 bug? The fact that it is crashing there may be the problem.

Yes, I did the Slider3 issue but it did not change anything .. the component with the error was just to send the slider state out via topic/payload message.

I dont think thatr this is an issue with the sliders because it is the same for the sliders and the v-button-toggles .. whenever a component has a dynamic element .. it does reset to the initial value as specified in the data section.

the console.log is always showing the last MSG which was published (see prev response_.. but does not show why the reset does occur.

Does the code behave on your system the same way?

latest code below:

[
    {
        "id": "6a974f23938f8edf",
        "type": "inject",
        "z": "b9b23c2bc52ffcbb",
        "name": "on",
        "props": [
            {
                "p": "payload.slider1",
                "v": "120",
                "vt": "str"
            },
            {
                "p": "payload.slider2",
                "v": "85",
                "vt": "str"
            },
            {
                "p": "payload.slider3",
                "v": "90",
                "vt": "str"
            },
            {
                "p": "payload.mode",
                "v": "DARK",
                "vt": "str"
            },
            {
                "p": "payload.state",
                "v": "true",
                "vt": "bool"
            },
            {
                "p": "payload.pos",
                "v": "34",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "x": 770,
        "y": 800,
        "wires": [
            [
                "363a684a0601c33f"
            ]
        ]
    },
    {
        "id": "363a684a0601c33f",
        "type": "ui-template",
        "z": "b9b23c2bc52ffcbb",
        "group": "a10c84096c0cdaa8",
        "name": "new light",
        "order": 1,
        "width": "0",
        "height": "0",
        "head": "",
        "format": "<template>\n  <v-card class=\"mx-auto\" width=\"100%\" color=\"grey\">\n    <template v-slot:title>\n      <v-card-title class=\"text-white font-weight-bold\" v-text=\"mylabel\"></v-card-title>\n      <v-card-subtitle class=\"text-white font-weight-bold\" v-text=\"mysub\"></v-card-subtitle>\n    </template>\n\n    <template v-slot:prepend>\n      <v-btn :icon=\"myicon\" :color=\"mystate_color\" @click=\"myupdate()\"></v-btn>\n    </template>\n\n    <template v-slot:append>\n      <v-btn-toggle v-model=\"mymode\" color=\"blue\" variant=\"elevated\" mandatory divided >\n        <v-btn icon=\"mdi-lightbulb-off-outline\" value=\"OFF\"></v-btn>\n        <v-btn icon=\"mdi-weather-sunny\" value=\"DAY\"></v-btn>\n        <v-btn icon=\"mdi-weather-sunset-down\" value=\"TWILIGHT\"></v-btn>\n        <v-btn icon=\"mdi-weather-night\" value=\"DARK\"></v-btn>\n        <v-btn icon=\"mdi-sleep\" value=\"SLEEP\"></v-btn>\n        <v-btn text=\"LUX\" value=\"LUX\"></v-btn>\n      </v-btn-toggle>\n    </template>\n\n    <v-progress-linear class=\"ma-2\" color=\"primary\" height=\"20\" :model-value=\"slider\" bg-opacity=\"0.6\" rounded>\n      <template v-slot:default=\"{ value }\">\n        <strong>{{mystate}} - {{mypos}}min / {{myduration}}min</strong>\n      </template>\n    </v-progress-linear>\n\n    <v-slider class=\"my-0\" v-model=\"slider1\" density=\"compact\" :max=\"mymax1\" :step=\"mystep1\" :label=\"mylabel1\"\n      color=\"purple\" :prepend-icon=\"myicon\" hide-details>\n      <template v-slot:append>\n        <v-text-field class=\"my-0\" v-model=\"slider1\" density=\"compact\" style=\"width: 80px\" type=\"number\"\n          variant=\"filled\" hide-details>\n        </v-text-field>\n      </template>\n    </v-slider>\n\n    <v-slider class=\"my-0\" v-model=\"slider2\" density=\"compact\" :max=\"mymax2\" :step=\"mystep2\" :label=\"mylabel2\"\n      color=\"purple\" :prepend-icon=\"myicon\" hide-details>\n      <template v-slot:append>\n        <v-text-field class=\"my-0\" v-model=\"slider2\" density=\"compact\" style=\"width: 80px\" type=\"number\"\n          variant=\"filled\" hide-details>\n        </v-text-field>\n      </template>\n    </v-slider>\n\n    <v-slider class=\"my-0\" v-model=\"slider3\" density=\"compact\" :max=\"mymax3\" :step=\"mystep3\" :label=\"mylabel3\"\n      color=\"purple\" :prepend-icon=\"myicon\" hide-details>\n      <template v-slot:append>\n        <v-text-field class=\"my-0\" v-model=\"slider3\" density=\"compact\" style=\"width: 80px\" type=\"number\" variant=\"filled\"\n          hide-details>\n        </v-text-field>\n      </template>\n    </v-slider>\n    \n  </v-card>\n</template>\n\n<script>\n  export default {\n    data: () => ({\n      myicon: 'mdi-lightbulb-on',\n      mylabel: 'Bedroom Light',\n      mylabel1: 'Timer [min]',\n      mylabel2: 'Brightness [%]',\n      mylabel3: 'min Lux {lux]',\n      slider: 0,\n      slider1: 0,\n      slider2: 0,\n      slider3: 0,\n\n      mymax: 180,\n      mymax1: 180,\n      mymax2: 100,\n      mymax3: 1000,\n\n      mystep: 10,\n      mystep1: 10,\n      mystep2: 10,\n      mystep3: 10,\n\n      mysub: 'motion mode',\n      mypos: '5',\n      myprogress: '70',\n      mystate: true,\n      mystate_color: 'blue',\n      myduration: '20',\n\n      myunit: 'mm',\n      mymode: 'OFF',\n      mydisabled: false,\n      toggle: null,\n      old_msg: null,\n    }),\n\n    watch: {\n      // watch for any changes of \"count\"\n  \n      msg: function () \n      {\n\n        console.log(`Message received: ${JSON.stringify(this.msg)}`)\n\n        if (this.msg.payload.slider1 != undefined) this.slider1=this.msg.payload.slider1;\n        if (this.msg.payload.slider2 != undefined) this.slider2=this.msg.payload.slider2;\n        if (this.msg.payload.slider3 != undefined) this.slider3=this.msg.payload.slider3;\n        \n        if (this.msg.payload.mode != undefined)  this.mymode=this.msg.payload.mode;\n        if (this.msg.payload.state != undefined) this.mystate=this.msg.payload.state;\n\n        if (this.msg.payload.pos != undefined) this.mypos=this.msg.payload.pos;\n\n\n        //this.send(this.msg);\n\n      },\n      mystate: function () {\n        if (this.mystate ==true) \n        {\n          this.mystate_color=\"blue\";\n        }\n        else\n        {\n          this.mystate_color=\"white\";\n        }\n\n      this.msg.payload=this.mystate;\n      this.msg.topic=\"CMD\";\n      this.send(this.msg)\n      },\n\n      mymode: function () {\n      this.msg.payload=this.mymode;\n      this.msg.topic=\"MODE\";\n      this.send(this.msg)\n      },\n\n      slider1: function () {\n      this.myduration=this.slider1;\n      this.slider=this.mypos/this.myduration*100;\n\n      this.msg.payload=this.slider1;\n      this.msg.topic=\"TIMER\";\n      this.send(this.msg)\n      },\n\n      slider2: function () {\n      this.msg.payload=this.slider2;\n      this.msg.topic=\"LEVEL\";\n      this.send(this.msg)\n      },\n\n      slider3: function () {\n      this.msg.payload=this.slider3;\n      this.msg.topic=\"minLUX\";\n      this.send(this.msg)\n      },\n\n    },\n    computed: {\n    // automatically compute this variable\n    // whenever VueJS deems appropriate\n    },\n    methods: {\n    // expose a method to our <template> and Vue Application\n            myupdate()\n            {        \n              if (this.mystate ==true)\n              {\n                this.mystate=false;\n              }\n              else\n              {\n                this.mystate=true;\n              }\n            }\n      },\n    mounted() {\n      // code here when the component is first loaded\n      },\n    unmounted() {\n      // code here when the component is removed from the Dashboard\n      // i.e. when the user navigates away from the page\n      }\n  \n  }\n</script>",
        "storeOutMessages": true,
        "passthru": false,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 920,
        "y": 820,
        "wires": [
            [
                "5ce8f56d6f1df0c7"
            ]
        ]
    },
    {
        "id": "62cdb1c94ddfcfe5",
        "type": "inject",
        "z": "b9b23c2bc52ffcbb",
        "name": "off",
        "props": [
            {
                "p": "payload.state",
                "v": "false",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 770,
        "y": 840,
        "wires": [
            [
                "363a684a0601c33f"
            ]
        ]
    },
    {
        "id": "5ce8f56d6f1df0c7",
        "type": "debug",
        "z": "b9b23c2bc52ffcbb",
        "name": "light out",
        "active": true,
        "tosidebar": true,
        "console": true,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 1070,
        "y": 820,
        "wires": []
    },
    {
        "id": "a10c84096c0cdaa8",
        "type": "ui-group",
        "name": "My Group",
        "page": "5294d297c3ed545d",
        "width": "6",
        "height": "1",
        "order": 1,
        "showTitle": true,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "5294d297c3ed545d",
        "type": "ui-page",
        "name": "Office Mirco",
        "ui": "a0ddd2d7af1545fc",
        "path": "/officemirco",
        "icon": "home",
        "layout": "notebook",
        "theme": "129e99574def90a3",
        "order": 6,
        "className": "",
        "visible": true,
        "disabled": "false"
    },
    {
        "id": "a0ddd2d7af1545fc",
        "type": "ui-base",
        "name": "DB2",
        "path": "/dashboard",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-notification",
            "ui-control"
        ],
        "showPathInSidebar": false,
        "navigationStyle": "default"
    },
    {
        "id": "129e99574def90a3",
        "type": "ui-theme",
        "name": "Another Theme",
        "colors": {
            "surface": "#000000",
            "primary": "#ffd500",
            "bgPage": "#a1a1a1",
            "groupBg": "#b3b3b3",
            "groupOutline": "#ffffff"
        },
        "sizes": {
            "pagePadding": "9px",
            "groupGap": "12px",
            "groupBorderRadius": "9px",
            "widgetGap": "6px"
        }
    }
]

log statement

catcher.js:135 [Deprecation] Listener added for a 'DOMNodeRemoved' mutation event. This event type is deprecated, and will be removed from this browser very soon. Usage of this event listener will cause performance issues today, and represents a large risk of future site breakage. Consider using MutationObserver instead. See https://chromestatus.com/feature/5083947249172480 for more information.
(anonymous) @ catcher.js:135
(anonymous) @ catcher.js:240
index-DNdRjf7c.js:47 setup {RED: {…}, socketio: {…}, basePath: '/dashboard'}
index-DNdRjf7c.js:239 SIO connected
index-DNdRjf7c.js:231 ui-config received. topic: a0ddd2d7af1545fc payload: {dashboards: {…}, heads: {…}, pages: {…}, themes: {…}, groups: {…}, …}
VM3461:2 Message received: {"payload":"DARK","_msgid":"bb50a913e3dc5a8c","topic":"MODE","_dashboard":{"sourceId":"363a684a0601c33f","templateId":"363a684a0601c33f"},"_client":{"socketId":"XYj0xMZBdXx2z5zNAAAf"}}

If I open the developer console in the browser, then click the On inject then switch back to the dashboard window in the browser and click F5 to refresh the page then I see

image

So as you can see the dashboard does send the last message sent out by the node. Do you not see that?
On refresh the template should receive the last message sent to it or sent from it.

Sorry, I did exactly the same steps .. and attached the log file .. I can see the last msg sent (as mentioned above) but I do not see any "Inavlid navigationStyle" in my log :frowning:

btw .. i copied the ui-template code into the VUE code test environment and it does behave the same way :frowning: .... adjusting the sliders ..than F5.. and all values are back to initial values.

I than used the original VUE example for Sliders and tested it in their test environment


... and it behaved the same way .. reset on F5

I'm now thinking this is a normal VUE behavior ... but how can I overcome the reset of values :frowning:

It isn't to do with VUE it is the way the dashboard interacts with templates.

When the browser is refreshed it sends back to you the last message that was sent to the template or from the template. In your case this is the last message that you sent, as you can see by comparing the browser console output with the debug log in node-red. This message does not have what your watch msg function is expecting which is why it resets everything.

To solve your problem, you have to make sure that any message you send to the template or send from the template has all the information you need to display it correctly. I do this by including a property which I call _data in any messages I send from the template. Then if I receive a message containing _data I know that it is caused by a refresh and I can use the contents of _data to set up the widgets.

2 Likes

Hi,

Sorry I don't want disturb this thread, but I had the same problem and could resolve it with the help of this thread.
Maybe my button example can help you.

1 Like

That sound good .. I will give it a try :slight_smile:

thanks @Colin your info was spot-on .. I used your suggestion and have updated my flow.. key changes are 2 new functions

  • myUpdate (topic, payload) .. ths function will update the ouput msg with topic,payload and all current data of the UI (in _data :wink: )
  • myReload() .. this function will check if any new msg has _data and will load the ui-values accordingly

now it works perfectly and I can apply this for all ui-templates with VUE elements

[
    {
        "id": "b8fc9abbed520636",
        "type": "inject",
        "z": "b9b23c2bc52ffcbb",
        "name": "on",
        "props": [
            {
                "p": "payload.slider1",
                "v": "120",
                "vt": "str"
            },
            {
                "p": "payload.slider2",
                "v": "85",
                "vt": "str"
            },
            {
                "p": "payload.slider3",
                "v": "90",
                "vt": "str"
            },
            {
                "p": "payload.mode",
                "v": "DARK",
                "vt": "str"
            },
            {
                "p": "payload.state",
                "v": "true",
                "vt": "bool"
            },
            {
                "p": "payload.pos",
                "v": "34",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "x": 223.00000762939453,
        "y": 1025.9999694824219,
        "wires": [
            [
                "98a1791464405afd"
            ]
        ]
    },
    {
        "id": "98a1791464405afd",
        "type": "ui-template",
        "z": "b9b23c2bc52ffcbb",
        "group": "a10c84096c0cdaa8",
        "name": "new light",
        "order": 1,
        "width": "0",
        "height": "0",
        "head": "",
        "format": "<template>\n  <v-card class=\"mx-auto\" width=\"100%\" color=\"grey\">\n    <template v-slot:title>\n      <v-card-title class=\"text-white font-weight-bold\" v-text=\"mylabel\"></v-card-title>\n      <v-card-subtitle class=\"text-white font-weight-bold\" v-text=\"mysub\"></v-card-subtitle>\n    </template>\n\n    <template v-slot:prepend>\n      <v-btn :icon=\"myicon\" :color=\"mystate_color\" @click=\"myState()\"></v-btn>\n    </template>\n\n    <template v-slot:append>\n      <v-btn-toggle v-model=\"mymode\" color=\"blue\" variant=\"elevated\" mandatory divided >\n        <v-btn icon=\"mdi-lightbulb-off-outline\" value=\"OFF\"></v-btn>\n        <v-btn icon=\"mdi-weather-sunny\" value=\"DAY\"></v-btn>\n        <v-btn icon=\"mdi-weather-sunset-down\" value=\"TWILIGHT\"></v-btn>\n        <v-btn icon=\"mdi-weather-night\" value=\"DARK\"></v-btn>\n        <v-btn icon=\"mdi-sleep\" value=\"SLEEP\"></v-btn>\n        <v-btn text=\"LUX\" value=\"LUX\"></v-btn>\n      </v-btn-toggle>\n    </template>\n\n    <v-progress-linear class=\"ma-2\" color=\"primary\" height=\"20\" :model-value=\"slider\" bg-opacity=\"0.6\" rounded>\n      <template v-slot:default=\"{ value }\">\n        <strong>{{mystate}} - {{mypos}}min / {{myduration}}min</strong>\n      </template>\n    </v-progress-linear>\n\n    <v-slider class=\"my-0\" v-model=\"slider1\" density=\"compact\" :max=\"mymax1\" :step=\"mystep1\" :label=\"mylabel1\"\n      color=\"purple\" :prepend-icon=\"myicon\" hide-details>\n      <template v-slot:append>\n        <v-text-field class=\"my-0\" v-model=\"slider1\" density=\"compact\" style=\"width: 80px\" type=\"number\"\n          variant=\"filled\" hide-details>\n        </v-text-field>\n      </template>\n    </v-slider>\n\n    <v-slider class=\"my-0\" v-model=\"slider2\" density=\"compact\" :max=\"mymax2\" :step=\"mystep2\" :label=\"mylabel2\"\n      color=\"purple\" :prepend-icon=\"myicon\" hide-details>\n      <template v-slot:append>\n        <v-text-field class=\"my-0\" v-model=\"slider2\" density=\"compact\" style=\"width: 80px\" type=\"number\"\n          variant=\"filled\" hide-details>\n        </v-text-field>\n      </template>\n    </v-slider>\n\n    <v-slider class=\"my-0\" v-model=\"slider3\" density=\"compact\" :max=\"mymax3\" :step=\"mystep3\" :label=\"mylabel3\"\n      color=\"purple\" :prepend-icon=\"myicon\" hide-details>\n      <template v-slot:append>\n        <v-text-field class=\"my-0\" v-model=\"slider3\" density=\"compact\" style=\"width: 80px\" type=\"number\" variant=\"filled\"\n          hide-details>\n        </v-text-field>\n      </template>\n    </v-slider>\n    \n  </v-card>\n</template>\n\n<script>\n  export default {\n    data: () => ({\n      myicon: 'mdi-lightbulb-on',\n      mylabel: 'Bedroom Light',\n      mylabel1: 'Timer [min]',\n      mylabel2: 'Brightness [%]',\n      mylabel3: 'min Lux {lux]',\n      slider: 0,\n      slider1: 0,\n      slider2: 0,\n      slider3: 0,\n\n      mymax: 180,\n      mymax1: 180,\n      mymax2: 100,\n      mymax3: 1000,\n\n      mystep: 10,\n      mystep1: 10,\n      mystep2: 10,\n      mystep3: 10,\n\n      mysub: 'motion mode',\n      mypos: '5',\n      myprogress: '70',\n      mystate: true,\n      mystate_color: 'blue',\n      myduration: '20',\n\n      myunit: 'mm',\n      mymode: 'OFF',\n    }),\n\n    watch: {\n      // watch for any changes of \"count\"\n  \n      msg: function () \n      {\n\n        console.log(`Message received: ${JSON.stringify(this.msg)}`)\n        this.myReload();\n        if (this.msg.payload.slider1 != undefined) this.slider1=this.msg.payload.slider1;\n        if (this.msg.payload.slider2 != undefined) this.slider2=this.msg.payload.slider2;\n        if (this.msg.payload.slider3 != undefined) this.slider3=this.msg.payload.slider3;\n        \n        if (this.msg.payload.mode != undefined)  this.mymode=this.msg.payload.mode;\n        if (this.msg.payload.state != undefined) this.mystate=this.msg.payload.state;\n\n        if (this.msg.payload.pos != undefined) this.mypos=this.msg.payload.pos;\n\n\n        //this.send(this.msg);\n\n      },\n      mystate: function () {\n        if (this.mystate ==true) \n        {\n          this.mystate_color=\"blue\";\n        }\n        else\n        {\n          this.mystate_color=\"white\";\n        }\n\n      this.msg.payload=this.mystate;\n      this.msg.topic=\"CMD\";\n      this.myUpdate(\"CMD\",this.mystate);\n      },\n\n      mymode: function () {\n      this.msg.payload=this.mymode;\n      this.msg.topic=\"MODE\";\n      this.myUpdate(\"MODE\",this.mymode);\n      },\n\n      slider1: function () {\n      this.myduration=this.slider1;\n      this.slider=this.mypos/this.myduration*100;\n\n      this.msg.payload=this.slider1;\n      this.msg.topic=\"TIMER\";\n      this.myUpdate(\"TIMER\",this.slider1);\n      },\n\n      slider2: function () {\n      this.msg.payload=this.slider2;\n      this.msg.topic=\"LEVEL\";\n      this.myUpdate(\"LEVEL\",this.slider2);\n      },\n\n      slider3: function () {\n      this.msg.payload=this.slider3;\n      this.msg.topic=\"minLUX\";\n      this.myUpdate(\"minLUX\",this.slider3);\n      },\n\n    },\n    computed: {\n    // automatically compute this variable\n    // whenever VueJS deems appropriate\n    },\n    methods: {\n    // expose a method to our <template> and Vue Application\n            myState()\n            {        \n              if (this.mystate ==true)\n              {\n                this.mystate=false;\n              }\n              else\n              {\n                this.mystate=true;\n              }\n            },\n            myReload: function()\n            {\n              console.log(`check reload: ${JSON.stringify(this.msg)}`)\n              if (this.msg._data !=undefined)\n              {\n                console.log(`loading old data: ${JSON.stringify(this.msg)}`)\n                //--- update data\n                this.slider = this.msg._data.slider;\n                this.slider1= this.msg._data.slider1;\n                this.slider2= this.msg._data.slider2,\n                this.slider3= this.msg._data.slider3;\n                \n                this.mymax= this.msg._data.mymax;\n                this.mymax1= this.msg._data.mymax1;\n                this.mymax2= this.msg._data.mymax2;\n                this.mymax3= this.msg._data.mymax3;\n                \n                this.mystep= this.msg._data.mystep;\n                this.mystep1= this.msg._data.mystep1;\n                this.mystep2= this.msg._data.mystep2;\n                this.mystep3= this.msg._data.mystep3;\n                \n                this.mysub= this.msg._data.mysub;\n                this.mypos= this.msg._data.mypos;\n                this.myprogress= this.msg._data.myprogress;\n                this.mystate= this.msg._data.mystate;\n                this.mymode= this.msg._data.mymode;\n                \n                this.mystate_color= this.msg._data.mystate_color;\n                this.myduration= this.msg._data.myduration;\n                \n              }\n\n            },\n            myUpdate: function(myTopic,myPayload)\n            {\n            // --- store all data into _data and send out all info as payload\n            \n            this.send('update');\n            //-------- prepare payload & topic ---------\n            this.msg.payload=myPayload;\n            this.msg.topic=myTopic;\n\n            //console.log(`updated msg: ${JSON.stringify(this.msg)}`)\n            \n            //-------- prepare all info for _data\n            let old={};\n\n            old.slider1= this.slider1;\n            old.slider2= this.slider2;\n            old.slider3= this.slider3;\n            \n            old.mymax= this.mymax;\n            old.mymax1= this.mymax1;\n            old.mymax2= this.mymax2;\n            old.mymax3= this.mymax3;\n            \n            old.mystep= this.mystep;\n            old.mystep1= this.mystep1;\n            old.mystep2= this.mystep2;\n            old.mystep3= this.mystep3;\n            \n            old.mysub = this.mysub;\n            old.mypos = this.mypos;\n            old.myprogress = this.myprogress;\n            old.mystate = this.mystate;\n            old.mymode = this.mymode;\n            \n            old.mystate_color = this.mystate_color;\n            old.myduration = this.myduration;\n\n            this.msg._data= old;\n            //--- send out payload\n            this.send(this.msg);\n            }\n      },\n    mounted() {\n      // code here when the component is first loaded\n      },\n    unmounted() {\n      // code here when the component is removed from the Dashboard\n      // i.e. when the user navigates away from the page\n      }\n  \n  }\n</script>",
        "storeOutMessages": true,
        "passthru": false,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 373.00000762939453,
        "y": 1045.9999694824219,
        "wires": [
            [
                "cc973af34966245a"
            ]
        ]
    },
    {
        "id": "9b1ff363d87fd532",
        "type": "inject",
        "z": "b9b23c2bc52ffcbb",
        "name": "off",
        "props": [
            {
                "p": "payload.state",
                "v": "false",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 223.00000762939453,
        "y": 1065.9999694824219,
        "wires": [
            [
                "98a1791464405afd"
            ]
        ]
    },
    {
        "id": "cc973af34966245a",
        "type": "debug",
        "z": "b9b23c2bc52ffcbb",
        "name": "light out",
        "active": true,
        "tosidebar": true,
        "console": true,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 523.0000076293945,
        "y": 1045.9999694824219,
        "wires": []
    },
    {
        "id": "a10c84096c0cdaa8",
        "type": "ui-group",
        "name": "My Group",
        "page": "5294d297c3ed545d",
        "width": "6",
        "height": "1",
        "order": 1,
        "showTitle": true,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "5294d297c3ed545d",
        "type": "ui-page",
        "name": "Office Mirco",
        "ui": "a0ddd2d7af1545fc",
        "path": "/officemirco",
        "icon": "home",
        "layout": "notebook",
        "theme": "129e99574def90a3",
        "order": 7,
        "className": "",
        "visible": true,
        "disabled": "false"
    },
    {
        "id": "a0ddd2d7af1545fc",
        "type": "ui-base",
        "name": "DB2",
        "path": "/dashboard",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-notification",
            "ui-control"
        ],
        "showPathInSidebar": false,
        "navigationStyle": "default"
    },
    {
        "id": "129e99574def90a3",
        "type": "ui-theme",
        "name": "Another Theme",
        "colors": {
            "surface": "#000000",
            "primary": "#ffd500",
            "bgPage": "#a1a1a1",
            "groupBg": "#b3b3b3",
            "groupOutline": "#ffffff"
        },
        "sizes": {
            "pagePadding": "9px",
            "groupGap": "12px",
            "groupBorderRadius": "9px",
            "widgetGap": "6px"
        }
    }
]

thanks a lot !!

Hi @Colin,
Thanks for sharing your experiences!
But it sounds to me that this is something the dashboard should offer out of the box, to make sure all ui nodes do it the same way. Because this kind of stuff made ui node development very difficult in the past.
Because I assume that @joepavitt have done something alike for all his core ui nodes...
I now start doubting if he already explained this. Too much on my head :exploding_head:

2 Likes

Hi @BartButenaers , I agree and hope it can be a default feature in future (or simplified) ... but for the moment it works and was a good learning experience :wink:

There was a discussion about providing access to the server side data store in ui-templates some time ago, @joepavitt was worried about people abusing it I think and overloading the socket. I agree that it would be worth re-visiting this however, managing state in a template is a bit of a pain at the moment.

1 Like

Could you open an issue please @Colin, summarise the use case of what youre trying to do, the shortcomings with D2.0 right now, and lets work out a solution.

P.s. Im away until the 11th, so will be quiet from my side

1 Like

Done: Provide access to a server site state store from ui-templates · Issue #939 · FlowFuse/node-red-dashboard · GitHub

2 Likes

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