Adding `output` function to buttons designed in `template` node

I do agree.

And how I would do this is to just have the button doing the basics.

It sends a message. I don't think it needs to be an on and off message. A simple message should suffice.
What the TV has done (though I don't know if the TV will actually tell me the mode) the state is then sent back to the node and it reflects the state.

As you see there is already two different ways proposed how to create logic for buttons with state.
I'm not going to say the one is better than the other.
But I recommend to choose one type of logic and do all the buttons in that way.

And again: I agree.

I think - and also to simplify what I need to learn about CSS - I think it would be better any smarts are done outside the node.

That way the button is more generic, which is what I think would be better at this point.

This is true, but if it is handled externally from the node, I can have a reduced number of places where this loss of sync can occur.

As each button would be a possible point of failure.
If I centralise it to a node, the points of failure is reduced.

Just on a general "OOPS!" moment, I got into a bit of a feedback loop because I forgot to un tick the pass through button in the template node.

Oops! :wink:

Andrew, the example I sent you (where the code to toggle the button and also accept input from node-red input) was a means of showing you how it could be done only.

If I was to implement this, I'd write ONE function that handles EVERY button.

This follows the DRY principal (i.e. write it once, use it many times) (ps, that's why we are getting you to do CSS classes - write them once & reuse)

This has the benefit of any bugs being limited to one fix.

To achieve this is harder than stated but it is possible.

Example....
Your button template would look (something like) this.

<div id="Mute">
   <md-button id="mute-button" class="md-button remote-button" 
              data-state="1"  
              data-button-type="toggle"
              data-topic="mute"
              data-icon1="volume_off"
              data-icon2="volume_up"
              aria-label="Mute">
      <i class="material-icons md-48">volume_off</i>
   </md-button>
</div>

^ zero code, fully portable and easy to implement.

A separate code block would take care of the JS, event handling, icon settings and swapping.

The benefit of this method is - only one place for script - you simply update the attributes of your buttons.

NOTE the above is a pseudo example (not usable) - it is intended to give you and hotnipi a possible direction.

Sorry Steve. I admit I got a bit carried away with it.

I fully get the "Write once and reuse" idea.
Alas it is susceptible all the same to different ways to optimisation.
And though that is a good node to use, it is limited in my scheme for usability.

Rather buttons that can:
1 - send a message when pressed. (Not too critical on what is sent)
2 - send two messages. One when pressed and one when released. (Again: Not too critical on payloads)
3 - accept inputs to set either the colour or icon, or in some cases both.

That kind of button would be a lot more usable to me. The other fancy stuff can be done outside the button in a function node to accommodate specific needs.

Again:
I am sorry, I did get a bit too caught up in the button you posted. I understand it wasn't meant for that. Just the excitement overtook me.

Anyway, thanks again for the help.
I do appreciate it.
It is nice to see other ways of doing things.

Something else has come to light and so a question:

I get this set of buttons working. They send their stuff to a node and all is good.

I want to use the same layout (get of buttons) in another flow - same machine.

I can't just copy them and move their copies to the other ..... tab? and they work.
I will have to rename all their innards to new, unique names.

though, why I am asking this is because I started doing it.
For now only buttons 1 - 9. 0 was left out for now.

Buttons 2 - 8 work. Button 1 refuses to.

Putting a debug node on the output, it isn't sending anything when I press it.

Ok...... Let's try to look at what is going on.

I go to the original button. (Skipping a couple of things - keeping it brief) If I press that 1, it works.

Ok..... Suspect.

I copy the code from that button: Open the template node, copy the code.
Paste it in the one which isn't working.
Click OK.

no change registered on button. I don't have the little blue The node has changed indicator.

I'd better stop here, as I am getting off topic for this thread.
But the original question kind of stands though:
Can I copy the buttons (template nodes) to another flow and use them there with no interference between them?

No worries Andrew.

This is what i mean by DRY (code written once only - but all buttons work)

It demonstrates every button working & firing unique topic/payloads, and also - icon toggling and click only type buttons...

BENEFITS...

  • All button templates are the same format with zero code (except 1*)
  • JS code is written once for ALL buttons with class remote-button
  • Simply give your button the class remote-button and set attributes data-payload (what to send) data-topic (what topic it should have)
  • for a toggle button, add attributes data-buttontype='toggle', data-icon0='icon_name' and data-icon1='icon_name'

* one of the button templates is used to host the code


NOTES...

  • All messages come out of the ONE NODE (the one with the code in)
    • msg.topic will have value you set in the buttons data-topic attribute
    • msg.payload will have the value you set in buttons data-payload attribute
    • with these 2 values, you can route the msg where ever it needs to go (using a switch or function node for example).
  • It is not ideal (i would prefer the code to be in HEAD template but i cant get scope code to work in the head)
  • this code could be placed in an empty non-head template instead if desired.

You are welcome to the code if you want it.

No problem if you dont need or dont want it. I enjoyed figuring this one out either way (and i have an personal / ulterior motive anyhow :slight_smile: )

Steve,

Wow! Thanks.

I still do have that code you posted but I got distracted with the mute button, as I am sure you saw.

I will have to give it a better look. (Alas as much as I do want to do this, I am sitting here with the idiot box (tv) on kind of distracting me) Though I need the TV on for testing the buttons in their ultimate use.

Just now I am having problems duplicating buttons from one tab to another.
I am not 100% sure, but it seems there is a problem with names - which I kind of get - I am trying to work out what is going on.

I also have a lot of InfraRed codes to copy into change nodes.
That way the buttons don't need to know them. I don't think it really saves much space program wise. Just rather than in one place, the InfraRed code is in another place.

That kind of good in that I can copy the layout to something else and use the same layout and just put in new change nodes with different InfraRed codes for another device.

Just ducking back, the nodes you have here are named differently to the one I have, and the one I have doesn't have any inject nodes.

Are the inject nodes the only real difference?

no, the 1st time i demoed the toggle button - it was written for 1 button (e.g. you would need to copy+paste the code for every button - i.e. poor design)

I revised that code to parameterise things & thus work with any number buttons (1 or 2 or 265 - however many you need)

PS, the inject buttons are simply there to demonstrate a server-side (node-red side) payload toggling the button (so you get true visual state)

If you say.

But the layout of what you showed me looks like the one I have.

Screenshot from 2020-04-27 21-30-26

So other than the name changes, I was confused. Don't worry. That is pretty much status quo for me.

You can post the code here or PM me with it. I am not biased either way.

Someone else may appreciate the effort as well as me.
:slight_smile:

(No offence)
I think I kind of steered away because it has the same template settings as the ones @hotNipi and I are using and it caused some clashes I think.
I'm not 100% sure, but I just went and disabled most other tabs... And of course your code was on another tab.

I'm just trying to keep things segmented. I know that is not the bigger idea, but at this early stage, it helps me find if there is a problem: who is causing it and be able to disable that tab rather than having to delete a lot of stuff on the same tab.

So that is what happened to be best of my knowledge to why I didn't look too closely at your code.
Again: Not that I don't want the help. I just got carried away with the other stuff.

of course.

Hope it helps you or someone else.

About...

Demonstrate ONE function for all buttons

  • All button templates are the same format with zero code (except 1*)
  • JS code is written once for ALL buttons with class remote-button
  • Simply give your button the class remote-button and set attributes data-payload (what to send) data-topic (what topic it should have)
  • for a toggle button, add attributes data-buttontype='toggle' , data-icon0='icon_name' and data-icon1='icon_name'

*** one of the button templates is used to host the code**

Visual Demo....

Flow...

[{"id":"f4fac1e9.e93e4","type":"ui_template","z":"e1dfad68.fee2a","group":"be17d3d4.a92a6","name":"CSS only ","order":7,"width":0,"height":0,"format":"<style id=\"remote-buttons\">\n    :root {\n      --dashboard-unit-width: 48px;\n      --dashboard-unit-height: 48px;\n    }\n    .nr-dashboard-template {\n        padding: 0px;\n    }\n    .remote-button:not([disabled]):hover{\n         background-color: #232323 !important;\n    }\n\n    /*   This is the normal button definition  */\n    .remote-button{\n        background-color: black !important;\n        color: #cccccc !important;\n        height: var(--dashboard-unit-height);\n        width: 100%;\n        border-radius: 10px;\n        font-size:1.0em;\n        font-weight:normal;\n        margin: 0;\n        min-height: 36px;\n        min-width: unset;\n        line-height: unset;\n    }\n    /*  This is a sub-set which is invoked by */\n    /*  <md-button class=\"md-button remote-button bigger\"> */\n    /*  note the (space) \"bigger\" at the end.  */\n    .remote-button.bigger{\n        font-weight:bold;\n        font-size:1.5em;\n    }\n    /*  This is for buttons with a lot of text.  `font-size:0.7em` */\n    /*  makes the font 70% normal size  */\n    .remote-button.small{\n        font-size:0.7em;\n    }\n    /*  This is for buttons with just icons, to upsize the size */\n    /*  of the icon with the line: */\n    /*  <i class=\"fa fa-fw fa-plus remote-icon\"> in the other node  */\n    .remote-icon{\n        font-size:2.0em;\n    }\n    /*  This is the same as the other one, but it makes the icon smaller  */\n    .remote-iconS{\n        font-size:0.5em;\n    }\n\n    .remote-button.black{\n        background-color: black !important;\n        color: #cccccc !important;\n    }\n\n    .remote-button.red{\n        background-color: red !important;\n        color: #cccccc !important;\n    }\n    .remote-button.red:not([disabled]):hover{\n         background-color: orange !important;\n    }\n</style>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"global","x":740,"y":60,"wires":[[]]},{"id":"bc691572.02ce88","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"NetFlix","order":20,"width":"1","height":"1","format":"<div>\n    <md-button \n        class=\"md-button remote-button\"\n        data-topic=\"netflix\"\n        data-payload=\"netflix\"\n        aria-label=\"Netflix\"\n    >\n        <img\n            class=\"remote-icon\"\n            style=\"width: 36px; padding-top: 2px\"\n            src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAE2klEQVR4Xu3bW4hVVRzH8c8ZE/GCtywry5qcarrhpbKLmoVl9FZ0s2zS0DIJrIceSl+EwIgIDCQCp4t2L4guBJUgTmnlXYtUirIpU9EZxyayqWbmxPKcARFn1hKDaW/7v64fM/v3Pf/1X2v/91oFx3kUjnP//gdwLBnQxMB2Hk75G81sreTNFO0CbioyKkX7Nwvnsz9FeyTNMWXAbip78kPKP29n++uMmkNzTL+AlzAtpgvjBSof48cU7b8O4Ckqp7G8B2elPMB2pl7KazFtZgA8wVkTWHI+V8dMhfE/eec0bolpMwWgNxtq6IeeMWM4sIzRU/i2K22mABTZPoUvB3BFAgD7mHcOC3IFoJKNkxmdAqCNTc9y2XxaO9NnLgPCUjKTnys4IwXCNm4Yxye5ARCMXEvduUxMAdBC7TDuyxWAPjTUMBAnJEBo/Jjqu2g4kjZzU6DDxJ2s7s/lCQA0cX8Vi3MFoIoNkxiTAqCV5UOZlCsABYoz2VnBsAQI7VsYM4HNh2szOwWCkUnUVSUWwwM8eQaP5gpAP/ZMZQgqYllQpP4Dqu+l5VBtpjMgGJnK2n5cFgMQxhu4+TzezRWAatZOTATQyttDuT1XACpon8meAqckZEFLPSPGsLNDm/kpEIxcT93ZicXwLx45ladzBWAAu6aUMiDadWpn8xBGh2U0QMhFBgQjd7OuL5cmTIOwMxxfxapcATifNVczNgVAO8+dxOxcAaigbSaNBU5OgNC0lTPH81tupkAwfSN1w9OL4bRTWZorAAPYMYXTEzIgVMDlQ5iUKwDB+D1s7J3WMise4LyXmZeJ7wKhLR6aorFf9yK+HJfYNG3n8cUMzxWAHrTO4NcCJ8Zg4ada6tqoSdB275eh1AwoF8MVw7kmxVQdn2xjcoq2Wz+NHQ2Awbx9G7em7Ax/5Ys3uDJXALBkVqlTdF2Csb+WcuCPUpO1y8hMBgQAD7CsyCsxU2H8az77nAkxbaYA1DC7D79gUMxYK989zzkxXaYAzGV6I89gTsxYGH+fbbuo7kqbOQD7uKh4MMPjsZvP3otMg8wBCLYbS6+9V8URaK6lVxu9OtNmEkAD0wu8mADAWj7f0AWsTALYSZ9epR7ggBiEFjYvYWSuMiCY2ceiIg/GAITxt9jR1MkbZSYzIJhqYmQ7m1IA/Ejdx530FDILoFwMV0tomRXZvZihxSM0WLMOYAZqU7JgOeu/45LDtZkGsId+PdildMqsy2hm9etHOHuQaQDlafAcZsUAoHUpzX8w+FBt5gHsZUwF6xMA+IZPVx52KDPzAMpL4vpiwsmSNr6vZUSuMqAMYFaRMBWi8SFbdnBBhzAXGdBIf6WdYd8Ygb2sfIfxuQJQLoZhOQzLYpdR5PcXqGildxDmIgOCkQbGFggbo2isY9V6xuUKQNjl7WOjLl58Osi08PUSLs4VgHIWPFhgUTQFSi9I9U2cmZspEEyX7yCFYnhwfncV9dR9xMRcASgXw9AomR4DUGRPLUOKjOi2O0NH82EktMVDUzRmrLHU/Tl4UiQWK1j7LbfnCkC5GIam6YUxAL+z5lXuyBWAcjGcUyi1z2PR9hVV13bXtbn5DOyZeHGywKa5h50I7czdfga18VDMfRivYOGg7ro4mfKA/3VN9Azff93AsT7fcQ/gH8HaMl8q26yhAAAAAElFTkSuQmCC\">\n        />\n    </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":730,"y":360,"wires":[[]]},{"id":"57de4e.f4cfb1b4","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"Home","order":21,"width":"1","height":"1","format":"<div>\n   <md-button class=\"md-button remote-button\" \n        data-topic=\"home\"\n        data-payload=\"home\" \n        aria-label=\"home\"\n    >\n    <i class=\"fa fa-home remote-icon\"> </i>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":360,"wires":[[]]},{"id":"a6df6e36.1d16b","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"Vid","order":22,"width":"1","height":"1","format":"<div>\n   <md-button class=\"md-button remote-button small\" \n        data-topic=\"video\"\n        data-payload=\"video\" \n    >Video\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":360,"wires":[[]]},{"id":"2a646eff.3f7cf2","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"1","order":2,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\">1\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":730,"y":120,"wires":[[]]},{"id":"ef0701c1.ddb63","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"2","order":3,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"2\"\n    data-payload=\"2\">2\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":120,"wires":[[]]},{"id":"a8296eda.ec9d6","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"3","order":4,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"3\"\n    data-payload=\"3\">3\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":120,"wires":[[]]},{"id":"cf65f510.c80d68","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"4","order":5,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"4\"\n    data-payload=\"4\">4\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":730,"y":160,"wires":[[]]},{"id":"84949bc8.2bd298","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"5","order":6,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"5\"\n    data-payload=\"5\">5\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":160,"wires":[[]]},{"id":"b341d1f1.adf42","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"6","order":7,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"6\"\n    data-payload=\"6\">6\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":160,"wires":[[]]},{"id":"76507e83.940e6","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"7","order":8,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"7\"\n    data-payload=\"7\">7\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":730,"y":200,"wires":[[]]},{"id":"fbafce7d.80576","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"8","order":9,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"8\"\n    data-payload=\"8\">8\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":200,"wires":[[]]},{"id":"684b5568.bf5c6c","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"9","order":10,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"9\"\n    data-payload=\"9\">9\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":200,"wires":[[]]},{"id":"114192b6.67ea7d","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"0","order":12,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"0\"\n    data-payload=\"0\">0\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":240,"wires":[[]]},{"id":"84c69bfc.13faa8","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"info","order":11,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\"\n    data-topic=\"info\"\n    data-payload=\"info\"\n    aria-label=\"info\"\n   >\n      <i class=\"fa fa-info-circle remote-icon\"></i>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":730,"y":240,"wires":[[]]},{"id":"25910d61.070c82","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"prev","order":13,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\"\n    data-topic=\"prev\"\n    data-payload=\"prev\"\n    aria-label=\"previous\"\n   >\n      <i class=\"fa fa-rotate-left remote-icon\"></i>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":240,"wires":[[]]},{"id":"787787b2.c80b88","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"Ch +","order":16,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\" \n        data-topic=\"channel/up\"\n        data-payload=\"up\" \n        aria-label=\"channel up\"\n    >\n    <i class=\"fa fa-chevron-up remote-icon\"></i>\n   </md-button>\n</div>\n\n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":280,"wires":[[]]},{"id":"7eb81447.3ea8dc","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"mute","order":15,"width":1,"height":1,"format":"<div>\n   <md-button id=\"mute-button\" class=\"md-button remote-button\" \n              data-payload=\"1\" \n              data-buttontype=\"toggle\"\n              data-topic=\"mute\"\n              data-icon0=\"volume_off\"\n              data-icon1=\"volume_mute\"\n              aria-label=\"volume mute\"\n              >\n      <i class=\"material-icons md-48\">volume_mute</i>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":280,"wires":[[]],"info":"  class=\"material-icons\"> volume_off"},{"id":"6eeb00d0.da35b","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"vol +  *","order":14,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\" \n        data-topic=\"volume/plus\"\n        data-payload=\"volume/plus\"\n        aria-label=\"volume plus\"\n    >\n    <span style=\"color:{{msg.colour}}\" class=\"fa fa-plus remote-icon\"> </span>\n   </md-button>\n</div>\n\n\n","storeOutMessages":true,"fwdInMessages":false,"templateScope":"local","x":730,"y":280,"wires":[[]],"info":"<div id=\"regular_plus\">\n   <md-button class=\"md-button remote-button\">\n      <i class=\"fa fa-plus remote-icon\"></i>\n   </md-button>\n</div>"},{"id":"c58bb5ab.ebc658","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"vol -  *","order":17,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\" \n        data-topic=\"volume/minus\"\n        data-payload=\"volume/minus\"\n        aria-label=\"volume minus\"\n    >\n    <span style=\"color:{{msg.colour}}\" class=\"fa fa-minus remote-icon\"> </span>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":false,"templateScope":"local","x":730,"y":320,"wires":[[]],"info":"<div id=\"regular_plus\">\n   <md-button class=\"md-button remote-button\">\n      <i class=\"fa fa-minus remote-icon\"></i>\n   </md-button>\n</div>\n"},{"id":"782351a7.0f3f6","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"ch list","order":18,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\"\n    data-topic=\"channel/list\"\n    data-payload=\"list\"\n    aria-label=\"channel list\"\n   >\n      <i class=\"fa fa-list-alt remote-icon\"></i>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":320,"wires":[[]]},{"id":"18ff979.4cf7768","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"Ch -","order":19,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\" \n        data-topic=\"channel/down\"\n        data-payload=\"down\" \n        aria-label=\"channel down\"\n    >\n    <i class=\"fa fa-chevron-down remote-icon\"></i>\n   </md-button>\n</div>\n\n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":320,"wires":[[]]},{"id":"6b43ca3e.3b35a4","type":"inject","z":"e1dfad68.fee2a","name":"","topic":"mute","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":690,"y":420,"wires":[["c322da00.abb3a8"]]},{"id":"54ff0f5c.2703e","type":"inject","z":"e1dfad68.fee2a","name":"","topic":"mute","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":690,"y":460,"wires":[["c322da00.abb3a8"]]},{"id":"c322da00.abb3a8","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"script for all buttons with class remote-button","order":23,"width":"1","height":"1","format":"<div>\n<!--diliberately emtpy - only need the script below -->\n</div>\n\n\n\n<script>\n\n(function($scope) {\n//debugger\n    setTimeout(function() {\n        //debugger\n        $scope.init();\n    },100);\n    \n    function isNumeric(n){\n        if(n === true || n === false) return false;\n        return !isNaN(parseFloat(n)) && isFinite(n)\n    }\n   \n    // in controller\n    $scope.init = function () {\n        //debugger\n        console.log(\"$scope.init called\")\n        var allButtons = $(\".remote-button\") \n        allButtons.click(function(e){\n            //debugger\n            var btn = $(this)\n            var type = btn.data(\"buttontype\");//get the button type from attribute data-buttontype=\"xxxxx\"\n            var payload = btn.data(\"payload\");//get the payload from attribute data-payload=\"xxxxx\"\n            //debugger\n            //if(isNumeric(payload))  payload = Number(payload);\n            \n            var topic = btn.data(\"topic\");//get the topic from attribute data-topic=\"xxxxx\"\n            if(type == \"toggle\"){\n                var newPayload = payload == 1 ? 0 : 1;\n                var $icon = btn.find(\"i\"); //get the <i> element\n                var newIcon = btn.data(\"icon\" + newPayload); //get icon1 or icon2 depending on newPayload\n                $icon.text(newIcon);\n                $scope.send({\"topic\":topic,\"payload\":newPayload})\n            } else {\n                $scope.send({\"topic\":topic,\"payload\":payload})\n            }\n        });\n    };\n    \n    //watch for node-red msgs\n    $scope.$watch('msg', function(msg) {\n        //debugger\n        if(!msg){ //if no msg \n            console.log(\"$scope.$watch('msg', ...) - msg is empty\");\n            return;\n        }\n        if(!msg.topic){ //if no topic set found\n            console.log(\"msg.topic is empty - cannot match this to any button\")\n            return; //stop processing!\n        }\n        var buttonSelector = \".remote-button[data-topic='\" + msg.topic + \"']\" \n        var $btn = $(buttonSelector);//get the button\n        \n        if(!$btn.length){ //if no button found\n            console.log(buttonSelector + \" not found - cannot set state\")\n            return; //stop processing!\n        }\n        \n        if($btn.length > 1){ //if MORE than one button found\n            console.log(buttonSelector + \" found more than 1 button - is this intended? Do you have the same data-topic set on multiple buttons?\")\n        }\n        \n        if($btn.data(\"buttontype\") === \"toggle\"){\n            if(msg.payload == \"1\"){\n                setButtonState($btn, 1);\n            } else if(msg.payload == \"0\"){\n                setButtonState($btn, 0);\n            } else {\n               console.log(\"Invalid toggle value in msg.payload, cannot set \" + buttonSelector + \". Ensure msg.payload is either 0 or 1\") \n            }\n        }\n\n    }); \n    \n    //helper function to set the correct icon & update the \"data-state\" memory\n    function setButtonState($btn, state){\n        $btn.data(\"payload\",state);//set data-payload to state\n        \n        //if icon is present, set it\n        var icon = $btn.data(\"icon\" + state);\n        if(icon){\n            var $ico = $btn.find(\"i\");\n            // $ico.removeClass(\"fa-volume_mute\") ;// font awesome version\n            // $ico.addClass(\"fa-volume_off\") ;// font awesome version\n            $ico.text(icon);//MDI version\n        }\n    }\n   \n\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":520,"wires":[["a90df8f.7eac108"]]},{"id":"a90df8f.7eac108","type":"debug","z":"e1dfad68.fee2a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":930,"y":460,"wires":[]},{"id":"be17d3d4.a92a6","type":"ui_group","z":"","name":"HOME","tab":"6af80cca.442cb4","order":1,"disp":true,"width":3,"collapse":false},{"id":"a381801e.309e1","type":"ui_group","z":"","name":"Full_Remote2","tab":"9e72c753.ebf048","order":3,"disp":false,"width":"3","collapse":false},{"id":"6af80cca.442cb4","type":"ui_tab","z":"","name":"TEST","icon":"dashboard","order":3,"disabled":false,"hidden":false},{"id":"9e72c753.ebf048","type":"ui_tab","z":"","name":"HDMI_TV_control","icon":"dashboard","order":7,"disabled":false,"hidden":false}]

Ok.

I have it working.

Just one thing:
Button 1.

It gives an undefined error.

No problems.

I worked it out.

The code is different to the other 9 number buttons.

Just asking: Was that just to check I am understanding? I'm not worried.
I went through pushing the buttons and of course starting at 1..... all the rest worked.

So I opened the template node and looked. Did the same with 2 and saw a difference.
Adjusted as needed and now it works.

By the way, this is a whole new way of doing it. (Yeah, ok, you did say that.)
It is 22:30 local and I've been up since 07:00-ish.

Interesting.

Yeah, this is really interesting. really interesting.

One question about the volume button/s:
Alas they don't send two messages. That is kind of needed only that if you hold the volume button down it keeps changing until it is released.

Sorry I can't post the link, but (I think it was you) that problem was worked around with a bit of code like this:

(The button goes between the two link nodes at the top)

[{"id":"5f10d2a2.d7607c","type":"link in","z":"1781e581.31721a","name":"","links":["69848a07.c10464"],"x":275,"y":1020,"wires":[["40429ed0.0fb288","baa7b104.5ae088"]]},{"id":"40429ed0.0fb288","type":"trigger","z":"1781e581.31721a","op1":"Down","op2":"0","op1type":"str","op2type":"str","duration":"-250","extend":false,"units":"ms","reset":"Up","bytopic":"all","name":"Repeat","x":400,"y":1010,"wires":[["11e3968c.d6de51"]]},{"id":"baa7b104.5ae088","type":"switch","z":"1781e581.31721a","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"Down","vt":"str"},{"t":"eq","v":"Up","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":390,"y":1050,"wires":[[],["11e3968c.d6de51"]]},{"id":"11e3968c.d6de51","type":"function","z":"1781e581.31721a","name":"toggle","func":"let c1 = \"lime\";\nlet c2 = \"red\";\nlet msg1 = {};\nlet y = context.get(\"pressed\") || 0;\nvar x = context.get(\"counter\") || 0;\nif (msg.payload == \"Up\")\n{\n    context.set(\"counter\",0);\n    msg.payload = \"A\";\n    msg.colour = c1;\n    context.set(\"pressed\",0);       //  Wipe count.\n//    msg1.colour = \"lime\";\n\n    return [msg,null];\n}\n\nif (x === 0)\n{\n    if (y === 0)\n    {\n        //  Send pressed message.\n        y = y + 1;\n        context.set(\"pressed\",y);\n        //  msg1 = {payload:\"Goo\"};\n        msg1 = {payload:\"Pressed\"};\n        msg1.colour = c2;\n        node.send([null,msg1]);\n        //node.send([null,msg1]);\n        \n    }\n    msg.payload = \"B\";\n    msg.colour = c2;\n    msg1.colour = c2;\n} else\nif (x === 1)\n{\n    msg.payload = \"A\";\n    msg.colour = c1;\n    msg1.colour = c1;\n}\n\nx = (x + 1) % 2;\n\ncontext.set(\"counter\",x);\n\nreturn [msg,null];","outputs":2,"noerr":0,"x":550,"y":1010,"wires":[["565220df.fb4738","b2f939.032cc6c8"],["60a6cac3.40877c"]]},{"id":"b2f939.032cc6c8","type":"link out","z":"1781e581.31721a","name":"","links":["8f960c13.389b9"],"x":645,"y":990,"wires":[]},{"id":"8f960c13.389b9","type":"link in","z":"1781e581.31721a","name":"","links":["b2f939.032cc6c8"],"x":305,"y":700,"wires":[["45e5a406.7764d4"]]},{"id":"69848a07.c10464","type":"link out","z":"1781e581.31721a","name":"","links":["5f10d2a2.d7607c","a084db85.97daf8","78b093ac.e42a84"],"x":504,"y":700,"wires":[]}]

The idea being that the button is pressed and sends a down message.
That starts the trigger node to send a stream of messages.
When the button is released, a up message is sent.
This stops the trigger node.

For the overheads, I am happy with doing it that way, as there are only two buttons which need this functionality.

But back to what you posted:
Yeah, it is a whole other perspective on how to do that.

(Sorry, @hotNipi. Not dismissing what you have done.)

I am really going to have to sit down and work out how that bottom template node works.

No need to be sorry for me.
The advises you'll get from @Steve-Mcl are very professional and I really recommend to follow them.
Just a little bit different but you'll get it soon and main thing, you'll get the results. Good results.

1 Like

As the code is in one place, it would be easy to invent a new buttontype "repeat on hold" for example.

Do you have a code example of this I could cut and paste and parameterise?

(I'm also just about to go to bed)
I'm torn between which is the better way.

Each has its strengths and weaknesses.

Steve's way makes button design so much easier.
But it then entails a lot more work being done by the template node. (As I just saw his reply come in)

I have invested a lot of designing in how you showed me, but I am now seeing problems with (as I mentioned) copying the buttons between web pages.... Will there be a conflict as they are global names - as I understand it.

(Though I guess Steve's method may have the same underlying problem.)

Brain starting to fail for today.

How his accepts attributes is a lot easier I feel.

I am not sure what work is needed to get either (or both) fully working.
Again: each has its strengths and weaknesses.

I think that may have to wait until tomorrow though. Eye lids are getting heavy and I have a bit of a headache too. So maybe I need sleep.

Thanks to you both.

Nope. Buttons and Divs don't require any names with the code I wrote.

1 Like

I think the best/only example I can give you is that snippet I posted.
How it detects the down message and starts the trigger node until it gets/sees an up message. Then stops.

For the external nodes needed, it is not essential the template node does that.
I am happy to leave it as is.

Maybe also so as to stop myself getting too far ahead of myself too quickly.
Sometimes that can be a whole new problem. :wink:

So that is something like inline CSS?
As opposed to internal which I am guessing is what is/was used now.