Can ui-button respond to double-click

Is it possible to add an action in response to a double click (distinct from single click) to a plain ui-button?

I also have the same question about a ui-list element.

Thanks for any help, pointers ...
chris

Welcome to the forum. Please remember there is a search function here.

These are current topics about similar queries

There might be some function code or some other hints that will help guide you to what you need.

1 Like

Also, search the palette for keywords, a little reading of the resultant pages may turn up a gem or two :slight_smile:

I wasn't aware of this node-contrib until I searched, due this topic.

It might be able to work with an input from a ui_button as well?? Test and see.

Hi @Gunner,
I wrote that node for physical buttons, e.g. read via a GPIO pin. Seems that this question is about double clicks on a ui-button in the dashboard.
I assume double clicks events are not handled at the moment? Have to leave for work (first day in 1,5 year not working from home) so cannot quickly test...

Not that I have implemented recently something similar in svg.
Bart

Yes, I did see that, but figured an input trigger is an input trigger.... but then later realized, as I was testing, that a ui_button, while visually acting like it would, doesn't seem to have an option for triggering on a "release"... which, belatedly, seems a very strange omission as it could otherwise easily be used as a "proper" multi-click button.

I have experimented with faked a release using a timed 0 inject, and that works for some of your node options, but getting the timing just right for a click or double click is a bit more difficult.

Actually, it doesn't trigger on the "press", rather it triggers on the "release"... strange that I never noted that before. It clearly detects the press visually, so why not trigger on both?

I did some searching before posting but almost everything that turned up seemed aimed at physical buttons. The only one related to a dashboard button (which you linked above earlier) seemed a bit flakey - author still working on detecting a single press vs the 4 he had achieved already.

If a double click isn't built into the ui-button (from replies so far I'm assuming it's not) I was hoping it could be done fairly easily with perhaps a function node following the ui-button and doing some sort of timing of successive clicks passed to it. I had a quick go at that myself but my node-red skills are still quite young so unsuccessful so far. I was hoping this was such an obvious need that someone had already implemented something or other.

here is a simple example hope it helps

[{"id":"f44c4a9.93ec0b8","type":"debug","z":"b779de97.b1b46","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":680,"y":2160,"wires":[]},{"id":"eeee73a8.90d11","type":"function","z":"b779de97.b1b46","name":"","func":"let time_then = context.get(\"button.\"+msg.topic) || 0;\nlet time_now = new Date().valueOf();\ncontext.set(\"button.\"+msg.topic, time_now)\nlet gap = 1000 // half a second\nif (time_now-time_then < gap){\n    return msg;\n}\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":520,"y":2420,"wires":[["f44c4a9.93ec0b8"]]},{"id":"51790b02.54047c","type":"ui_button","z":"b779de97.b1b46","name":"","group":"8b5cde76.edd58","order":8,"width":0,"height":0,"passthru":true,"label":"button","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"str","topic":"topic","topicType":"str","x":340,"y":2420,"wires":[["eeee73a8.90d11"]]},{"id":"305cb4a0.ab8554","type":"inject","z":"b779de97.b1b46","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":2420,"wires":[["51790b02.54047c"]]},{"id":"8b5cde76.edd58","type":"ui_group","name":"","tab":"8f03e639.85956","order":1,"disp":true,"width":"12","collapse":false},{"id":"8f03e639.85956","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]
1 Like

I thought there was a multi-press dashboard node that someone had contributed, but I can't find it on the flows site. It did single, double, long press. Possibly more.

Here is something I got working using @BartButenaers contrib-button-events with ui_button

Since the button only triggers a 1 on release, the delay and function send a 0 50ms after, thus the button event node just gets the expected 1/0 pulse. I turned off debounce in that node.

[{"id":"51790b02.54047c","type":"ui_button","z":"f55aff94e50a53a7","name":"","group":"8b5cde76.edd58","order":8,"width":0,"height":0,"passthru":true,"label":"button","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"str","topic":"topic","topicType":"str","x":450,"y":440,"wires":[["7f44dff2bf42afe3","cfeb5a66fbec53e2"]]},{"id":"305cb4a0.ab8554","type":"inject","z":"f55aff94e50a53a7","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":290,"y":440,"wires":[["51790b02.54047c"]]},{"id":"7f44dff2bf42afe3","type":"button-events","z":"f55aff94e50a53a7","name":"","outputs":2,"inputField":"payload","inputFieldType":"msg","outputField":"payload","outputFieldType":"msg","downValue":"1","downValueType":"num","upValue":"0","upValueType":"num","idleValue":"1","clickedInterval":200,"pressedInterval":200,"debounceInterval":"","events":[{"type":"clicked"},{"type":"double_clicked"}],"x":700,"y":440,"wires":[["6c10a4584f7552e0"],["fe75590b63d8f503"]]},{"id":"cfeb5a66fbec53e2","type":"delay","z":"f55aff94e50a53a7","name":"","pauseType":"delay","timeout":"50","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"x":470,"y":500,"wires":[["b244b62de007c19e"]]},{"id":"b244b62de007c19e","type":"function","z":"f55aff94e50a53a7","name":"","func":"msg.payload = 0;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":500,"wires":[["7f44dff2bf42afe3"]]},{"id":"6c10a4584f7552e0","type":"counter","z":"f55aff94e50a53a7","name":"","init":"0","step":"1","lower":"","upper":"","mode":"increment","outputs":2,"x":900,"y":400,"wires":[["891967f5f46d8ec6"],[]]},{"id":"891967f5f46d8ec6","type":"ui_text","z":"f55aff94e50a53a7","group":"8b5cde76.edd58","order":17,"width":0,"height":0,"name":"","label":"Clicked","format":"{{msg.payload}}","layout":"row-center","x":1060,"y":400,"wires":[]},{"id":"fe75590b63d8f503","type":"counter","z":"f55aff94e50a53a7","name":"","init":"0","step":"1","lower":"","upper":"","mode":"increment","outputs":2,"x":900,"y":460,"wires":[["0600be2dabfbb429"],[]]},{"id":"0600be2dabfbb429","type":"ui_text","z":"f55aff94e50a53a7","group":"8b5cde76.edd58","order":18,"width":0,"height":0,"name":"","label":"Dbl Clicked","format":"{{msg.payload}}","layout":"row-center","x":1070,"y":460,"wires":[]},{"id":"8b5cde76.edd58","type":"ui_group","name":"","tab":"8f03e639.85956","order":1,"disp":true,"width":"12","collapse":false},{"id":"8f03e639.85956","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

And right after that... I saw a post by @UnborN that simply creates a dashboard button with proper press and release :+1:

I have added that to my flow... no need for the timer for that button :smiley:

[{"id":"81fc920712f2501c","type":"ui_template","z":"4895ea10b4ee9ead","group":"e68f0343d6bbfce5","name":"","order":0,"width":0,"height":0,"format":"<button id=\"myBtn\">Click Me</button>\n\n<script>\n(function(scope) {\n\nlet myBtn = document.getElementById('myBtn')\n\nmyBtn.addEventListener('mousedown', e => {\nscope.send({payload: 1})\n});\n\nmyBtn.addEventListener('mouseup', e => {\nscope.send({payload: 0})\n});\n\n})(scope);\n\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":650,"y":660,"wires":[["d53f0843a11651ea"]]},{"id":"d53f0843a11651ea","type":"debug","z":"4895ea10b4ee9ead","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":830,"y":660,"wires":[]},{"id":"e68f0343d6bbfce5","type":"ui_group","name":"Default","tab":"773981483ece4bf8","order":1,"disp":true,"width":"6","collapse":false},{"id":"773981483ece4bf8","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

2 Likes

Thanks for that Gunner- easily modified to detect click & dblclick events.

Also a good demo for node-red noob like me on how to use template node with javascript for ui elements.

Thanks for the example E1cid. It's good in that it detects double click just fine; however it doesn't signal single click. Simply modifying the function node to generate a second output for single clicks (anything not a double click) doesn't work because (I guess) the first click of a double is also interpreted as a single click on its own.

Just add a trigger node e.g

[{"id":"305cb4a0.ab8554","type":"inject","z":"b779de97.b1b46","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":2420,"wires":[["51790b02.54047c"]]},{"id":"51790b02.54047c","type":"ui_button","z":"b779de97.b1b46","name":"","group":"8b5cde76.edd58","order":8,"width":0,"height":0,"passthru":true,"label":"button","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"str","topic":"topic","topicType":"str","x":340,"y":2420,"wires":[["eeee73a8.90d11","d5219e44.4149c8"]]},{"id":"eeee73a8.90d11","type":"function","z":"b779de97.b1b46","name":"","func":"let time_then = context.get(\"button.\"+msg.topic) || 0;\nlet time_now = new Date().valueOf();\ncontext.set(\"button.\"+msg.topic, time_now)\nlet gap = 500 // half a second\nif (time_now-time_then < gap){\n    msg.reset = true;\n    return msg;\n}\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":520,"y":2420,"wires":[["f44c4a9.93ec0b8","d5219e44.4149c8"]]},{"id":"d5219e44.4149c8","type":"trigger","z":"b779de97.b1b46","name":"","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"600","extend":false,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":540,"y":2360,"wires":[["c1b26c81.635b7"]]},{"id":"c1b26c81.635b7","type":"debug","z":"b779de97.b1b46","name":"one","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":710,"y":2360,"wires":[]},{"id":"f44c4a9.93ec0b8","type":"debug","z":"b779de97.b1b46","name":"two","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":650,"y":2200,"wires":[]},{"id":"8b5cde76.edd58","type":"ui_group","name":"","tab":"8f03e639.85956","order":1,"disp":true,"width":"12","collapse":false},{"id":"8f03e639.85956","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

Great! Works with trigger node added. I'll mark this one as the solution because it works using the ui-button node as originally requested.

Here is a better one that will do 1 to nth clicks depending on delay

[{"id":"305cb4a0.ab8554","type":"inject","z":"b779de97.b1b46","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":2420,"wires":[["51790b02.54047c"]]},{"id":"51790b02.54047c","type":"ui_button","z":"b779de97.b1b46","name":"","group":"8b5cde76.edd58","order":8,"width":0,"height":0,"passthru":true,"label":"button","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"str","topic":"topic","topicType":"str","x":300,"y":2460,"wires":[["eeee73a8.90d11","1425d47b.a983bc"]]},{"id":"eeee73a8.90d11","type":"function","z":"b779de97.b1b46","name":"","func":"let count = flow.get(\"button_count\") || 0;\nflow.set(\"button_count\", count+1);\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":520,"y":2420,"wires":[[]]},{"id":"1425d47b.a983bc","type":"trigger","z":"b779de97.b1b46","name":"","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"600","extend":true,"overrideDelay":false,"units":"ms","reset":"","bytopic":"topic","topic":"topic","outputs":1,"x":230,"y":2500,"wires":[["591f7ae8.8f36c4"]]},{"id":"591f7ae8.8f36c4","type":"change","z":"b779de97.b1b46","name":"","rules":[{"t":"move","p":"button_count","pt":"flow","to":"button_count","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":2500,"wires":[["c987027d.3e03f"]]},{"id":"c987027d.3e03f","type":"switch","z":"b779de97.b1b46","name":"","property":"button_count","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"num"},{"t":"gte","v":"4","vt":"num"}],"checkall":"false","repair":false,"outputs":4,"x":600,"y":2500,"wires":[["c1b26c81.635b7"],["f44c4a9.93ec0b8"],["b303a5f2.fd925"],["84d1ac47.6f4678"]]},{"id":"c1b26c81.635b7","type":"debug","z":"b779de97.b1b46","name":"one","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":750,"y":2460,"wires":[]},{"id":"f44c4a9.93ec0b8","type":"debug","z":"b779de97.b1b46","name":"two","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":750,"y":2500,"wires":[]},{"id":"b303a5f2.fd925","type":"debug","z":"b779de97.b1b46","name":"three","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":750,"y":2540,"wires":[]},{"id":"84d1ac47.6f4678","type":"debug","z":"b779de97.b1b46","name":"otherwise","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":770,"y":2580,"wires":[]},{"id":"8b5cde76.edd58","type":"ui_group","name":"","tab":"8f03e639.85956","order":1,"disp":true,"width":"12","collapse":false},{"id":"8f03e639.85956","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

[change delay for trigger]

Hmmm... After a few failed attempts of my own, I had actually tried the flow from @E1cid before I had made the one I posted above. But couldn't get anything but a "1" out of it.

Same with this last one... What gives? I am clicking fast, clicking slow, clicking with and without looking, I think I tried once with my forehead... but that might have been counter-productive :stuck_out_tongue:

EDIT... ahhh forget it... I was looking at the payload, not the payload's node of source.

I fixed that :wink:

image

Just for info

I found that it was slightly unstable with repeated operations in quick sucsession, So I did the context storage with a change node, this seems more stable. Seems the change node is faster at context storage than the function node.

[{"id":"305cb4a0.ab8554","type":"inject","z":"b779de97.b1b46","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":2420,"wires":[["51790b02.54047c"]]},{"id":"51790b02.54047c","type":"ui_button","z":"b779de97.b1b46","name":"","group":"8b5cde76.edd58","order":8,"width":0,"height":0,"passthru":true,"label":"button","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"str","topic":"topic","topicType":"str","x":340,"y":2420,"wires":[["1425d47b.a983bc","2d6f28b0.9130e8"]]},{"id":"1425d47b.a983bc","type":"trigger","z":"b779de97.b1b46","name":"","op1":"","op2":"click","op1type":"nul","op2type":"str","duration":"300","extend":true,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":230,"y":2580,"wires":[["591f7ae8.8f36c4"]]},{"id":"2d6f28b0.9130e8","type":"change","z":"b779de97.b1b46","name":"","rules":[{"t":"set","p":"button_count","pt":"flow","to":"$flowContext(\"button_count\") ? $flowContext(\"button_count\")+1 : 1","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":570,"y":2380,"wires":[[]]},{"id":"591f7ae8.8f36c4","type":"change","z":"b779de97.b1b46","name":"","rules":[{"t":"move","p":"button_count","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":2580,"wires":[["c987027d.3e03f"]]},{"id":"c987027d.3e03f","type":"switch","z":"b779de97.b1b46","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"num"},{"t":"gte","v":"4","vt":"num"}],"checkall":"false","repair":false,"outputs":4,"x":600,"y":2500,"wires":[["c1b26c81.635b7"],["f44c4a9.93ec0b8"],["b303a5f2.fd925"],["84d1ac47.6f4678"]]},{"id":"c1b26c81.635b7","type":"debug","z":"b779de97.b1b46","name":"one","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":750,"y":2460,"wires":[]},{"id":"f44c4a9.93ec0b8","type":"debug","z":"b779de97.b1b46","name":"two","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":750,"y":2500,"wires":[]},{"id":"b303a5f2.fd925","type":"debug","z":"b779de97.b1b46","name":"three","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":750,"y":2540,"wires":[]},{"id":"84d1ac47.6f4678","type":"debug","z":"b779de97.b1b46","name":"otherwise","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":770,"y":2580,"wires":[]},{"id":"eeee73a8.90d11","type":"function","z":"b779de97.b1b46","name":"","func":"let count = flow.get(\"button_count\") || 0;\nflow.set(\"button_count\", count+1);\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":590,"y":2420,"wires":[[]]},{"id":"8b5cde76.edd58","type":"ui_group","name":"","tab":"8f03e639.85956","order":1,"disp":true,"width":"12","collapse":false},{"id":"8f03e639.85956","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

Able to lower the delay to 300 ms with the change node.
[edit]
here it is in series so no cloning msg

[{"id":"bb1e93fd.77c1c8","type":"inject","z":"b779de97.b1b46","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":310,"y":2340,"wires":[["f5b92924.1ec458"]]},{"id":"f5b92924.1ec458","type":"ui_button","z":"b779de97.b1b46","name":"","group":"8b5cde76.edd58","order":9,"width":0,"height":0,"passthru":true,"label":"button","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"str","topic":"topic","topicType":"str","x":480,"y":2340,"wires":[["3ad88553.1142ba"]]},{"id":"3ad88553.1142ba","type":"change","z":"b779de97.b1b46","name":"","rules":[{"t":"set","p":"button_count","pt":"flow","to":"$flowContext(\"button_count\")+1","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":680,"y":2340,"wires":[["28de7702.0fe7b8"]]},{"id":"28de7702.0fe7b8","type":"trigger","z":"b779de97.b1b46","name":"","op1":"","op2":"button_count","op1type":"nul","op2type":"flow","duration":"300","extend":true,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":330,"y":2460,"wires":[["24e7e11b.be52c6"]]},{"id":"24e7e11b.be52c6","type":"change","z":"b779de97.b1b46","name":"","rules":[{"t":"set","p":"button_count","pt":"flow","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":2460,"wires":[["7a2bf890.c32e48"]]},{"id":"7a2bf890.c32e48","type":"switch","z":"b779de97.b1b46","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"num"},{"t":"gte","v":"4","vt":"num"}],"checkall":"false","repair":false,"outputs":4,"x":751.3333129882812,"y":2468.333251953125,"wires":[["20756b78.8afdbc"],["c9dd4afe.854dc"],["d6b0378d.f72988"],["e4799362.09814"]]},{"id":"20756b78.8afdbc","type":"debug","z":"b779de97.b1b46","name":"one","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":891.3333129882812,"y":2428.333251953125,"wires":[]},{"id":"c9dd4afe.854dc","type":"debug","z":"b779de97.b1b46","name":"two","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":891.3333129882812,"y":2468.333251953125,"wires":[]},{"id":"d6b0378d.f72988","type":"debug","z":"b779de97.b1b46","name":"three","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":891.3333129882812,"y":2508.333251953125,"wires":[]},{"id":"e4799362.09814","type":"debug","z":"b779de97.b1b46","name":"otherwise","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":910,"y":2540,"wires":[]},{"id":"8b5cde76.edd58","type":"ui_group","name":"","tab":"8f03e639.85956","order":1,"disp":true,"width":"12","collapse":false},{"id":"8f03e639.85956","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

First time used will set context, then functions as normal

1 Like

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