UI-List multi users wrong behaviour

Hello,

I found that many UI nodes are synchronized from a Dashboard instance to another, but others are not. The UI-List, for instance, doesn't. Is there an easy way to make it synchronized for multiple instances of Dasbhoard?

I mean when a user check a box, others users would see the same box checked.

Thank you

If you read the documentation it is clear that Dashboard is single instance, single user.

There are alternatives but you lose the convenience of the pre-built elements.

I think (though I may be wrong) that @Andydesjardins' question is about how to get the ui list widget so show the same on all views of the dashboard, rather than the how to get differenct views for different users.

1 Like

Ah, thanks I misread that.

Yeah my goal is to have a single user UI. But if there's a second user that access Dashboard, I get inconsistant behaviours depending on the node used.

I haven't used ui-list. When one user checks a box does that get sent to node-red? Obviously before it is sent there is no way another user will see it.

Yes. We used a lot UI_List before upgrading to UI-List (UI_List now deprecated). But on both versions, we have the same issue. It works very well when a single Dashboard instance is used, but not sync on multiple.

In all cases Node-Red receive de data.

can you add a debug after the ui-list set to show whole message and show us an example ?

This is what a pass to the UI-List (checkbox mode):

msg: object
	_msgid: "e598a160.09189"
	topic: ""
	payload: array[3]
		0: object
			title: "this is title 1"
			description: "this is description 1"
		1: object
			title: "this is title 2"
			description: "this is description 2"
		2: object
			title: "this is title 3"
			description: "this is description 3"

And this is what goes out of UI-List

msg : object
	payload: object
	title: "this is title 2"
	description: "this is description 2"
	isChecked: true
	socketid: "6kq_q9pOA1eTZcXCAAAA"
	_msgid: "3c07620d.d24b5e"

Any idea?

yeah... as what comes out is not useable as an input to other nodes of the same type (unlike say a switch or slider which just have a value), then other instances of the node can't just receive that output (internally) and update themselves.

Not sure if there is an easy answer to this... (if at all). Will need some thinking about...
Can you raise an issue against the node on github so we can at least log and track it.
Thanks

1 Like

Thank you dceejay,

I created an issue:

Thanks...

I have similar issue. in the exported flow, I included a slider, switch and text from the dashboard widgets. they all synchronize across multiple browsers, however the template (toggleSwitch) does not. I tried researching on google and here, and tried to incorporate some of the comments to no avail. Any suggestions of where to search also, or what to try next would be appreciated.

"""
[{"id":"abca746d.25fe98","type":"tab","label":"Main","disabled":false,"info":""},{"id":"cefb0ab4.2f32d","type":"ui_template","z":"abca746d.25fe98","group":"e244ef19.ea7a5","name":"ToggleSwitch","order":2,"width":0,"height":0,"format":"\n.divSwOnOff{position:relative;display:flex;flex-direction:row;width:100%;margin:0px;}.switches{display:inline-block;position:relative;text-align:left;height:30px;background-color:#222;overflow:hidden;-webkit-box-shadow:inset 0 1px 2px black,0 1px 0 rgba(255,255,255,0.1);\n-moz-box-shadow:inset 0 1px 2px black,0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 2px black,0 1px 0 rgba(255,255,255,0.1);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;margin:1px 4px 0px auto;}.swOnOff{width:100px;}.switches input{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;margin:1px 0;cursor:pointer;opacity:0;filter:alpha(opacity=0);z-index:2;}.switches label {background-color:#3c3c3c;background-image:-webkit-linear-gradient(-40deg,rgba(0,0,0,0),rgba(255,255,255,0.1),rgba(0,0,0,0.2));background-image:-moz-linear-gradient(-40deg,rgba(0,0,0,0),rgba(255,255,255,0.1),rgba(0,0,0,0.2));background-image:-ms-linear-gradient(-40deg,rgba(0,0,0,0),rgba(255,255,255,0.1),rgba(0,0,0,0.2));background-image:-o-linear-gradient(-40deg,rgba(0,0,0,0),rgba(255,255,255,0.1),rgba(0,0,0,0.2));background-image:linear-gradient(-40deg,rgba(0,0,0,0),rgba(255,255,255,0.1),rgba(0,0,0,0.2));-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;display:inline-block;width:32px;text-align:center;font:bold 11px/28px Arial,Sans-Serif;text-shadow:0 -1px 0 rgba(0,0,0,0.7);-webkit-transition:margin-left 0.2s ease-in-out;-moz-transition:margin-left 0.2s ease-in-out;-ms-transition:margin-left 0.2s ease-in-out;-o-transition:margin-left 0.2s ease-in-out;transition:margin-left 0.2s ease-in-out;margin:1px 2px;}\n.switches label:before{content:attr(data-off);}.swOnOff label{color:gold;}.swOnOff input:checked + label{margin-left:66px;background-color:#006000;color:white;}.swOnOff input:checked + label:before{content:attr(data-on);}\n\n<script src="js/ui_toggle.js">\nvar action=false;function Actioned(){action=true;}\n(function($scope) {\n\t$scope.sendRow = function(tpc, ID, typ) {\n\t\tif (action) {\n\t\t\tvar retMsg={"topic":"","payload":{"Command":"Action","Payload":[{"ID":"","Type":1,"Value":0}]}};\n\t\t\tretMsg.topic ="axiomSH/TO/"+tpc;\n\t\t\tretMsg.payload.Payload[0].ID=ID;\n\t\t\tretMsg.payload.Payload[0].Type=typ;\n\t\t\tretMsg.payload.Payload[0].Value = (document.getElementById(ID).checked?1:0);\n\t\t\t$scope.send(retMsg);\n\t\t\taction=false;\n\t\t}\n\t};\n\t$scope.$watch('msg.payload', function(data) {\n\t\tif (data.Command==="Set") {\n//\t\t\tconsole.log('Position 5');\n//\t\t\tconsole.dir(data);\n\t\t\tdocument.getElementById(data.Payload[0].ID).checked=data.Payload[0].Value;\n\t\t}\n\t});\n})(scope); \n\n\n<div style="display:none;" id="thePayload" ng-bind-html="msg.payload">\n<div style="display:none;" id="theTopic" ng-bind-html="msg.topic">\n<div class="divSwOnOff">\t\n<span style="flex:1; margin-left:6px;">Label Here\n<span class="switches swOnOff">\n <input type="checkbox" name="lrLed" id="l2" onmouseup="Actioned();" ontouchend="Actioned();" ng-change="sendRow('LivingR','l2',1);" ng-model="myValue"/>\n <label data-on="ON" data-off="OFF">\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":410,"y":140,"wires":[["21d4a00a.b861e"]]},{"id":"3f08009d.897a18","type":"inject","z":"abca746d.25fe98","name":"","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":260,"wires":[["6005ed95.6aa1d4"]]},{"id":"ed1e8d8.7bb8ef","type":"inject","z":"abca746d.25fe98","name":"","topic":"","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":200,"wires":[["6005ed95.6aa1d4"]]},{"id":"6005ed95.6aa1d4","type":"function","z":"abca746d.25fe98","name":"","func":"var jsn ={"Command":"Set","Payload":[{"ID":"l2","Type":1,"Value":0}]};\njsn.Payload[0].Value=msg.payload?1:0;\nmsg.payload=jsn;\nreturn msg;","outputs":1,"noerr":0,"x":270,"y":140,"wires":[["cefb0ab4.2f32d"]]},{"id":"e7597a9f.24537","type":"debug","z":"abca746d.25fe98","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":730,"y":140,"wires":},{"id":"bd85f7ed.13377","type":"ui_text_input","z":"abca746d.25fe98","name":"","label":"","tooltip":"","group":"e244ef19.ea7a5","order":2,"width":0,"height":0,"passthru":true,"mode":"text","delay":300,"topic":"","x":540,"y":300,"wires":[]},{"id":"a2a561e7.3764b","type":"ui_slider","z":"abca746d.25fe98","name":"","label":"slider","tooltip":"","group":"e244ef19.ea7a5","order":3,"width":0,"height":0,"passthru":true,"outs":"all","topic":"","min":0,"max":10,"step":1,"x":550,"y":180,"wires":[["e7597a9f.24537"]]},{"id":"21d4a00a.b861e","type":"function","z":"abca746d.25fe98","name":"","func":"if (msg.payload.Payload[0].Value===1) msg.payload=true; else msg.payload=false;\nreturn msg;","outputs":1,"noerr":0,"x":550,"y":140,"wires":[["e7597a9f.24537"]]},{"id":"fde9bc79.d15f4","type":"ui_switch","z":"abca746d.25fe98","name":"","label":"switch","tooltip":"","group":"e244ef19.ea7a5","order":4,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":550,"y":240,"wires":[["e7597a9f.24537"]]},{"id":"e244ef19.ea7a5","type":"ui_group","z":"","name":"Lights","tab":"5c7e3cb9.4dc504","order":1,"disp":true,"width":"6","collapse":false},{"id":"5c7e3cb9.4dc504","type":"ui_tab","z":"","name":"Living Room","icon":"fa-tv","order":2,"disabled":false,"hidden":false}]

Thankyou

Please read up on how to post code in the forum. Thanks.

(apologies on phone so not looked at your code) - but maybe try adding a change node after the switch and delete msg.socketid before passing it on to the rest of the flow

Thank you for your reply. I did add a change node and deleted the socketid, still can't synchronize the template node. Seems like the built in nodes have features turned on or have attributes that I cannot find searching google and nodered.org site. If I solve this synchronization issue then I will tackle to to turn this into a ui-contributed widget:)

[{"id":"abca746d.25fe98","type":"tab","label":"Main","disabled":false,"info":""},{"id":"cefb0ab4.2f32d","type":"ui_template","z":"abca746d.25fe98","group":"e244ef19.ea7a5","name":"ToggleSwitch","order":2,"width":0,"height":0,"format":"<style>\n.divSwOnOff{position:relative;display:flex;flex-direction:row;width:100%;margin:0px;}.switches{display:inline-block;position:relative;text-align:left;height:30px;background-color:#222;overflow:hidden;-webkit-box-shadow:inset 0 1px 2px black,0 1px 0 rgba(255,255,255,0.1);\n-moz-box-shadow:inset 0 1px 2px black,0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 2px black,0 1px 0 rgba(255,255,255,0.1);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;margin:1px 4px 0px auto;}.swOnOff{width:100px;}.switches input{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;margin:1px 0;cursor:pointer;opacity:0;filter:alpha(opacity=0);z-index:2;}.switches label {background-color:#3c3c3c;background-image:-webkit-linear-gradient(-40deg,rgba(0,0,0,0),rgba(255,255,255,0.1),rgba(0,0,0,0.2));background-image:-moz-linear-gradient(-40deg,rgba(0,0,0,0),rgba(255,255,255,0.1),rgba(0,0,0,0.2));background-image:-ms-linear-gradient(-40deg,rgba(0,0,0,0),rgba(255,255,255,0.1),rgba(0,0,0,0.2));background-image:-o-linear-gradient(-40deg,rgba(0,0,0,0),rgba(255,255,255,0.1),rgba(0,0,0,0.2));background-image:linear-gradient(-40deg,rgba(0,0,0,0),rgba(255,255,255,0.1),rgba(0,0,0,0.2));-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;display:inline-block;width:32px;text-align:center;font:bold 11px/28px Arial,Sans-Serif;text-shadow:0 -1px 0 rgba(0,0,0,0.7);-webkit-transition:margin-left 0.2s ease-in-out;-moz-transition:margin-left 0.2s ease-in-out;-ms-transition:margin-left 0.2s ease-in-out;-o-transition:margin-left 0.2s ease-in-out;transition:margin-left 0.2s ease-in-out;margin:1px 2px;}\n.switches label:before{content:attr(data-off);}.swOnOff label{color:gold;}.swOnOff input:checked + label{margin-left:66px;background-color:#006000;color:white;}.swOnOff input:checked + label:before{content:attr(data-on);}\n</style>\n<script src=\"js/ui_toggle.js\">\nvar action=false;function Actioned(){action=true;}\n(function($scope) {\n\t$scope.sendRow = function(tpc, ID, typ) {\n\t\tif (action) {\n\t\t\tvar retMsg={\"topic\":\"\",\"payload\":{\"Command\":\"Action\",\"Payload\":[{\"ID\":\"\",\"Type\":1,\"Value\":0}]}};\n\t\t\tretMsg.topic =\"axiomSH/TO/\"+tpc;\n\t\t\tretMsg.payload.Payload[0].ID=ID;\n\t\t\tretMsg.payload.Payload[0].Type=typ;\n\t\t\tretMsg.payload.Payload[0].Value = (document.getElementById(ID).checked?1:0);\n\t\t\t$scope.send(retMsg);\n\t\t\taction=false;\n\t\t}\n\t};\n\t$scope.$watch('msg.payload', function(data) {\n\t\tif (data.Command===\"Set\") {\n//\t\t\tconsole.log('Position 5');\n//\t\t\tconsole.dir(data);\n\t\t\tdocument.getElementById(data.Payload[0].ID).checked=data.Payload[0].Value;\n\t\t}\n\t});\n})(scope);    \n</script>\n<div class=\"divSwOnOff\" ng-model=\"myValue\" >\t\n<span style=\"flex:1; margin-left:6px;\">Label Here</span>\n<span class=\"switches swOnOff\" >\n    <input type=\"checkbox\"  name=\"lrLed\" id=\"l2\" onmouseup=\"Actioned();\" ontouchend=\"Actioned();\" ng-change=\"sendRow('LivingR','l2',1);\" ng-model=\"myValue\"/>\n    <label data-on=\"ON\" data-off=\"OFF\"></label></span></div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":390,"y":100,"wires":[["d528504d.f06ab"]]},{"id":"3f08009d.897a18","type":"inject","z":"abca746d.25fe98","name":"","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":70,"y":220,"wires":[["6005ed95.6aa1d4"]]},{"id":"ed1e8d8.7bb8ef","type":"inject","z":"abca746d.25fe98","name":"","topic":"","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":70,"y":160,"wires":[["6005ed95.6aa1d4"]]},{"id":"6005ed95.6aa1d4","type":"function","z":"abca746d.25fe98","name":"","func":"var jsn ={\"Command\":\"Set\",\"Payload\":[{\"ID\":\"l2\",\"Type\":1,\"Value\":0}]};\njsn.Payload[0].Value=msg.payload?1:0;\nmsg.payload=jsn;\nreturn msg;","outputs":1,"noerr":0,"x":250,"y":100,"wires":[["cefb0ab4.2f32d"]]},{"id":"e7597a9f.24537","type":"debug","z":"abca746d.25fe98","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":710,"y":100,"wires":[]},{"id":"bd85f7ed.13377","type":"ui_text_input","z":"abca746d.25fe98","name":"","label":"","tooltip":"","group":"e244ef19.ea7a5","order":2,"width":0,"height":0,"passthru":true,"mode":"text","delay":300,"topic":"","x":520,"y":260,"wires":[[]]},{"id":"a2a561e7.3764b","type":"ui_slider","z":"abca746d.25fe98","name":"","label":"slider","tooltip":"","group":"e244ef19.ea7a5","order":3,"width":0,"height":0,"passthru":true,"outs":"all","topic":"","min":0,"max":10,"step":1,"x":530,"y":140,"wires":[["e7597a9f.24537"]]},{"id":"21d4a00a.b861e","type":"function","z":"abca746d.25fe98","name":"","func":"if (msg.payload.Payload[0].Value===1) msg.payload=true; else msg.payload=false;\nreturn msg;","outputs":1,"noerr":0,"x":710,"y":20,"wires":[["e7597a9f.24537"]]},{"id":"fde9bc79.d15f4","type":"ui_switch","z":"abca746d.25fe98","name":"","label":"switch","tooltip":"","group":"e244ef19.ea7a5","order":4,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":530,"y":200,"wires":[["e7597a9f.24537"]]},{"id":"d528504d.f06ab","type":"change","z":"abca746d.25fe98","name":"","rules":[{"t":"delete","p":"socketid","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":60,"wires":[["21d4a00a.b861e"]]},{"id":"e244ef19.ea7a5","type":"ui_group","z":"","name":"Lights","tab":"5c7e3cb9.4dc504","order":1,"disp":true,"width":"6","collapse":false},{"id":"5c7e3cb9.4dc504","type":"ui_tab","z":"","name":"Living Room","icon":"fa-tv","order":2,"disabled":false,"hidden":false}]

Ah right - you aren't actually returning anything from that templated node.

Thanks,
I did check and when I press it I get the following in the debug window:
2/25/2020, 12:29:57 AMnode: e7597a9f.24537axiomSH/TO/LivingR : msg : Object
object
topic: "axiomSH/TO/LivingR"
payload: true
_msgid: "df91a00c.5c45b"

If I press the dashboard switch, for example I get
2/25/2020, 12:32:18 AMnode: e7597a9f.24537msg : Object
object
payload: true
socketid: "sCrH1dYxXP-EJGXQAAAV"
_msgid: "b73885b0.925f58"

Difference is my template does not have socketid (i removed it) and the dashboard switch does not have a topic.

I noticed something that when I press the inject node (true or false) it does work, also I added a MQTT in, and when I send a message it does work. Only when I press the switch that it doesn't work.

My homework is trying to find the difference between pressing and receiving an inject or MQTT message :smiley: