Data not retained with a browser refresh

Hi,

Need some pointers with my flow. Created a dashboard using the UI template, but the data does not stay when the browser is refreshed. New data works fine. old data is not saved when going to other tabs or refreshing the browser.

Thanks..

My code:

[{"id":"1216b5f.e3e174a","type":"link in","z":"951edfe8.b734a","name":"","links":["19476d28.d37093"],"x":275,"y":120,"wires":[["f773df5c.75ecb"]]},{"id":"f773df5c.75ecb","type":"switch","z":"951edfe8.b734a","name":"Switching circuit based on name","property":"payload.name","propertyType":"msg","rules":[{"t":"eq","v":"MS-Livingroom","vt":"str"},{"t":"eq","v":"MS-Rumpus","vt":"str"},{"t":"eq","v":"MS-Entrance","vt":"str"},{"t":"eq","v":"DS-Rumpussliding","vt":"str"},{"t":"eq","v":"DS-Rumpuswindow","vt":"str"},{"t":"eq","v":"DS-Garageaccess","vt":"str"},{"t":"eq","v":"DS-Roofaccess","vt":"str"}],"checkall":"false","outputs":7,"x":290,"y":200,"wires":[["cc73d0b7.cae44","26e2bf34.5f0e7"],["cc73d0b7.cae44","26e2bf34.5f0e7"],["cc73d0b7.cae44","26e2bf34.5f0e7"],["cc73d0b7.cae44","26e2bf34.5f0e7"],["cc73d0b7.cae44","26e2bf34.5f0e7"],["cc73d0b7.cae44","26e2bf34.5f0e7"],["cc73d0b7.cae44","26e2bf34.5f0e7"]]},{"id":"cc73d0b7.cae44","type":"debug","z":"951edfe8.b734a","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":560,"y":100,"wires":[]},{"id":"5a754ff3.5c391","type":"ui_template","z":"951edfe8.b734a","group":"1de5adb1.9aa352","name":"Sensors","order":0,"width":"6","height":"9","format":"<h2 class=\"header2\">Motion Sensors</h2>\n<md-divider></md-divider>\n\n<!--Only div and creating flow -->\n<div class=\"main\">\n <div class=\"name\" flex =\"70\">\n <p class=\"text\">Living Room {{msliving}}</p>\n </div>\n <div class=\"icons\" flex=\"30\">\n <md-button \n class=\"md-raised btn\"\n ng-disabled=\"true\"\n ng-model=\"mybutton\"\n ng-click=\"btn(button)\" >\n <md-icon class=\"icon\" \n md-svg-src=\"{{mslivingroom == 0 ? '/nomotion.svg' : '/motiondetected.svg' }}\" \n style=\"\">\n </md-icon>\n </md-button>\n </div>\n</div>\n<!--Only div and creating flow -->\n<div class=\"main\">\n <div class=\"name\" flex =\"70\">\n <p class=\"text\">Rumpus</p>\n </div>\n <div class=\"icons\" flex=\"30\">\n <md-button \n class=\"md-raised btn\"\n ng-disabled=\"true\"\n ng-model=\"mybutton\"\n ng-click=\"btn(button)\" >\n <md-icon class=\"icon\" \n md-svg-src=\"{{msrumpus == 0 ? '/nomotion.svg' : '/motiondetected.svg' }}\" \n style=\"\">\n </md-icon>\n </md-button>\n </div>\n</div>\n<!--Only div and creating flow -->\n<div class=\"main\">\n <div class=\"name\" flex =\"70\">\n <p class=\"text\">Entrance</p>\n </div>\n <div class=\"icons\" flex=\"30\">\n <md-button \n class=\"md-raised btn\"\n ng-disabled=\"true\"\n ng-model=\"mybutton\"\n ng-click=\"btn(button)\" >\n <md-icon class=\"icon\" \n md-svg-src=\"{{msentrance == 0 ? '/nomotion.svg' : '/motiondetected.svg' }}\" \n style=\"\">\n </md-icon>\n </md-button>\n </div>\n</div>\n<!-- Creating the second part of the UI -->\n<md-divider></md-divider>\n<h2 class=\"header2\">Door Sensors</h2>\n<md-divider></md-divider>\n<!--Only div and creating flow -->\n<div class=\"main\">\n <div class=\"name\" flex =\"70\">\n <p class=\"text\">Garage Access</p>\n </div>\n <div class=\"icons\" flex=\"30\">\n <md-button \n class=\"md-raised btn\"\n ng-disabled=\"true\"\n ng-model=\"mybutton\"\n ng-click=\"btn(button)\" >\n <md-icon class=\"icon\" \n md-svg-src=\"{{dsgarageaccess != 0 ? '/dooropen.svg' : '/doorclose.svg' }}\" \n style=\"\">\n </md-icon>\n </md-button>\n </div>\n</div>\n<!--Only div and creating flow -->\n<div class=\"main\">\n <div class=\"name\" flex =\"70\">\n <p class=\"text\">Rumpus Sliding</p>\n </div>\n <div class=\"icons\" flex=\"30\">\n <md-button \n class=\"md-raised btn\"\n ng-disabled=\"true\"\n ng-model=\"mybutton\"\n ng-click=\"btn(button)\" >\n <md-icon class=\"icon\" \n md-svg-src=\"{{dsrumpussliding != '0' ? '/dooropen.svg' : '/doorclose.svg' }}\" \n style=\"\">\n </md-icon>\n </md-button>\n </div>\n</div>\n<!--Only div and creating flow -->\n<div class=\"main\">\n <div class=\"name\" flex =\"70\">\n <p class=\"text\">Roof Access</p>\n </div>\n <div class=\"icons\" flex=\"30\">\n <md-button \n class=\"md-raised btn\"\n ng-disabled=\"true\"\n ng-model=\"mybutton\"\n ng-click=\"btn(button)\" >\n <md-icon class=\"icon\" \n md-svg-src=\"{{dsroofaccess != '0' ? '/dooropen.svg' : '/doorclose.svg' }}\" \n style=\"\">\n </md-icon>\n </md-button>\n </div>\n</div>\n<!--Only div and creating flow -->\n<div class=\"main\">\n <div class=\"name\" flex =\"70\">\n <p class=\"text\">Rumpus Window</p>\n </div>\n <div class=\"icons\" flex=\"30\">\n <md-button \n class=\"md-raised btn\"\n ng-disabled=\"true\"\n ng-model=\"mybutton\"\n ng-click=\"btn(button)\" >\n <md-icon class=\"icon\" \n md-svg-src=\"{{dsrumpuswindow != '0' ? '/dooropen.svg' : '/doorclose.svg' }}\" \n style=\"\">\n </md-icon>\n </md-button>\n </div>\n</div>\n\n\n<script>\n // Lambda function to access the Angular Scope\n ;(function(scope) {\n \n //Watching the msg for any change\n scope.$watch('msg.payload', function(newVal, oldVal) {\n //console.log('- Scope.watch -');\n //console.dir(scope.msg);\n //Check sensor name\n if(scope.msg.payload.Sensor==\"MS-Livingroom\"){\n //console.log('- Scope.If MS-Livingroom condition -');\n //console.dir(scope.msg.payload.Data);\n if(scope.msg.payload.Data == 0){\n scope.mslivingroom = 0;\n }else{\n scope.mslivingroom = 1;\n }\n }\n if(scope.msg.payload.Sensor==\"MS-Rumpus\"){\n //console.log('- Scope.If MS-Rumpus condition -');\n //console.dir(scope.msg.payload.Data);\n if(scope.msg.payload.Data == 0){\n scope.msrumpus = 0;\n }else{\n scope.msrumpus = 1;\n }\n }\n if(scope.msg.payload.Sensor==\"MS-Entrance\"){\n //console.log('- Scope.If MS-Entrance condition -');\n //console.dir(scope.msg.payload.Data);\n if(scope.msg.payload.Data == 0){\n scope.msentrance = 0;\n }else{\n scope.msentrance = 1;\n }\n }\n if(scope.msg.payload.Sensor==\"DS-Garageaccess\"){\n //console.log('- Scope.If DS-Garageaccess condition -');\n //console.dir(scope.msg.payload.Data);\n if(scope.msg.payload.Data == 0){\n scope.dsgarageaccess = 0;\n }else{\n scope.dsgarageaccess = 1;\n }\n }\n if(scope.msg.payload.Sensor==\"DS-Roofaccess\"){\n //console.log('- Scope.If DS-Roofaccess condition -');\n //console.dir(scope.msg.payload.Data);\n if(scope.msg.payload.Data == 0){\n scope.dsroofaccess = 0;\n }else{\n scope.dsroofaccess = 1;\n }\n }\n if(scope.msg.payload.Sensor==\"DS-Rumpuswindow\"){\n //console.log('- Scope.If DS-Rumpuswindow condition -');\n //console.dir(scope.msg.payload.Data);\n if(scope.msg.payload.Data == 0){\n scope.dsrumpuswindow = 0;\n }else{\n scope.dsrumpuswindow = 1;\n }\n }\n if(scope.msg.payload.Sensor==\"DS-Rumpussliding\"){\n //console.log('- Scope.If DS-Rumpussliding condition -');\n //console.dir(scope.msg.payload.Data);\n if(scope.msg.payload.Data == 0){\n scope.dsrumpussliding = 0;\n }else{\n scope.dsrumpussliding = 1;\n }\n }\n \n \n })\n /*\n //send data based on button\n scope.btn = function(button) {\n scope.mybutton = (scope.textdata !=\"OFF\" ? 0 : 100 );\n console.log('- Scope.button -');\n console.dir(scope.msg.payload.svalue1);\n console.dir(scope.mybutton);\n scope.send({payload:scope.mybutton});\n }\n //send data based on slider\n scope.click = function(slider) {\n var slidervalue = scope.msg.payload.svalue1;\n console.log('- Scope.slider -');\n console.dir(slidervalue);\n scope.send({payload:slidervalue});\n }*/\n \n \n \n \n })(scope)\n</script>\n\n<style>\n .header2{\n text-align:center;\n }\n .main{\n height:60px !important;\n }\n .name{\n float:left !important;\n padding-top: 10px;\n }\n .icons{\n float:right !important;\n }\n .icon{\n height:32px !important;\n width:32px !important;\n }\n .text{\n color:teal !important;\n }\n \n</style>","storeOutMessages":true,"fwdInMessages":false,"templateScope":"local","x":880,"y":220,"wires":[[]]},{"id":"41a34b81.d9af64","type":"link in","z":"951edfe8.b734a","name":"","links":["46dfeb88.60e9b4"],"x":275,"y":260,"wires":[["cb1795e9.575288"]]},{"id":"cb1795e9.575288","type":"switch","z":"951edfe8.b734a","name":"Switching circuit based on name","property":"payload.Name","propertyType":"msg","rules":[{"t":"eq","v":"MS-Livingroom","vt":"str"},{"t":"eq","v":"MS-Rumpus","vt":"str"},{"t":"eq","v":"MS-Entrance","vt":"str"},{"t":"eq","v":"DS-Rumpussliding","vt":"str"},{"t":"eq","v":"DS-Rumpuswindow","vt":"str"},{"t":"eq","v":"DS-Garageaccess","vt":"str"},{"t":"eq","v":"DS-Roofaccess","vt":"str"}],"checkall":"false","outputs":7,"x":290,"y":340,"wires":[["2e91c9b9.d394c6"],["2e91c9b9.d394c6"],["2e91c9b9.d394c6"],["2e91c9b9.d394c6"],["2e91c9b9.d394c6"],["2e91c9b9.d394c6"],["2e91c9b9.d394c6"]]},{"id":"26e2bf34.5f0e7","type":"change","z":"951edfe8.b734a","name":"Create MSG","rules":[{"t":"move","p":"payload.Name","pt":"msg","to":"payload.Sensor","tot":"msg"},{"t":"move","p":"payload.Status","pt":"msg","to":"payload.Data","tot":"msg"},{"t":"move","p":"payload.name","pt":"msg","to":"payload.Sensor","tot":"msg"},{"t":"move","p":"payload.nvalue","pt":"msg","to":"payload.Data","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":220,"wires":[["23242263.9d294e","5a754ff3.5c391"]]},{"id":"23242263.9d294e","type":"debug","z":"951edfe8.b734a","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":970,"y":360,"wires":[]},{"id":"2e91c9b9.d394c6","type":"change","z":"951edfe8.b734a","name":"Create MSG","rules":[{"t":"move","p":"payload.Name","pt":"msg","to":"payload.Sensor","tot":"msg"},{"t":"move","p":"payload.Status","pt":"msg","to":"payload.Data","tot":"msg"},{"t":"change","p":"payload.Data","pt":"msg","from":"Off","fromt":"str","to":"0","tot":"num"},{"t":"change","p":"payload","pt":"msg","from":"On","fromt":"str","to":"1","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":260,"wires":[["5a754ff3.5c391","23242263.9d294e"]]},{"id":"1de5adb1.9aa352","type":"ui_group","z":"","name":"Sensors","tab":"10e406cd.0d5349","disp":true,"width":"6","collapse":false},{"id":"10e406cd.0d5349","type":"ui_tab","z":"","name":"Keypad","icon":"dashboard"}]

Most probably this behavior is happening because you are using the template node. Have you tried to sketch the same user interface by using the switch node and customizing the "on" and "off" icons?

Thanks, I will try, but the customization cannot be done as i could do in a UI template.

Yes, that is the advantage of the ui_template node – you can do whatever you want with the UI. The downside is that you may need to handle more of the UI logic, including initializing and saving state (depending upon your widgets – ymmv).

One technique I’ve used in the past is to place a single ui_control node in the first Editor tab (my understanding is that the first tab executes before the others when node-red starts up). That node sends out a msg whenever the user selects one of the dashboard pages from the left-hand nav menu. By detecting the user’s request to switch to that page, I can use a flow that gets all the data needed to render that page, and pass it back to the ui nodes, to update them (e.g. requery a database to update a chart, or in your case resend the switch states from whatever context was used to store them).

Thanks, That explains a lot.

I was thinking there was a problem in my flow.

Cheers

@shrickus - I believe this is the same issue I'm having. I'm using two different template nodes, each representing a tab (dashboard page). When I switch tabs using the left-hand nav menu, I'm losing the current state of the tab I'm leaving. When I navigate back to that initial tab the UI is reset to its original state without data.

What do you mean by your 'first Editor tab'? Would I add a ui_control to the group of nodes that comprise the first tab/page of the dashboard?

If you have template nodes where visible outcome depends on incoming data then you can use the ui_control node as the injector for data (re)feed as at every tab change and new connection the ui_control fires message. No mater of the contents of that message, the event is important and you can feed your nodes with (most relevant) data again. But as the tab name is carried in ui_control message, you can filter out only necessary nodes to "wake up". There is no need to use more than one ui_control for this use case. You can connect it with relevant nodes using link nodes.

2 Likes

Thanks @hotNipi. I'll give that a shot!