How to activate dynamically created UI switches

I've used this flow https://gist.github.com/DeanCording/1541bcbba48bb088ec1503dba109f63c to dynamically create a set of md-switches on my UI corresponding to my sonoff devices.

How do I "connect" these dynamically created UI elements such that they reflect the current state and cause an action when clicked. I understand how to do these things if the UI switches were individually, manually defined, but can't see how to incorporate a dynamic switch into a sequence.

You need to connect any update messages from your SONOFF's to the UI. Typically, you would use MQTT for this as it lets you subscribe to the appropriate update messages directly and feed the outputs direct to the Dashboard element.

I put up a thread about my "Coffee Pot Timer" project that has a SonOff S20 with a coffee pot plugged into it. I have a dashboard button (the 'cup' that when you click it, it sends a message to the S20 to turn the pot on and starts a 20 minute count down timer that eil shut the plug off if I forget to (the reason I built the flow).

You might want to install it and examine it to learn what I did.

Thanks for the answers, but they're kinda missing the point. My fault for wording the Q badly. I have mqtt, etc etc already up and running fine. I can manually declare a UI switch for each device and connect it up to my mqtt node, and that's all working fine too.

My question is specifically about how do I connect a dynamically created UI switch, ie. a switch created with template and therefore which doesn't exist in any of my flows.

Providing your flow would be a step in the right direction. Then people could see what you are already doing/not doing.

Ah, that's slightly different. But similar.

Firstly, you need to make sure that, when you dynamically create your switches, each gets a unique, repeatable ID. Preferably an ID that directly relates to the originating MQTT topic to make things simple. Then you will have to link things together via a flow. Without specifics it is hard to be clearer.

The link to the flow is in the question

The flow that creates the UI switches is in the question. My flow that drives the sonoffs is quite complex, but is outside of the scope of my question. Let's just say that when I toggle a UI switch I want to create a simple message with a payload of "toggle" that I want to route to a Debug node. I'm really really cool with how to drive sonoffs using MQTT. My question is all about how to "you will have to link things together via a flow". Remember these UI switches were created dynamically so do not appear in any flows.

OK, but that is not relavent. As you have created the Dashboard Template yourself, it is up to you to include code in the template such that, when the switch is activated, it sends back a suitable message indicating the ID if the switch activated.

There are plenty of examples around of how to send a msg back to Node-RED. The only thing you are really missing is making sure that the msg that is sent back contains an identifier that you can link to the appropriate sonoff.

So, starting from the example you've linked to, you need to add an on-click event handler that triggers a JavaScript function with a single parameter that is passed in from the button. My Angular is a bit rusty or I would give you an example. You populate the parameter from the device variable that you receive from the loop.

The function does a msg.send back to Node-RED containing a suitable msg.topic related to the ID you've passed in, the payload need only be "toggle" or something else.

Once back in Node-RED, you connect the output from your template node to something that passes the msg onward to MQTT, processing the topic if it doesn't exactly match your SONOFF device topic.

Cool thx.
It's the "There are plenty of examples around of how to send a msg back to Node-RED" that I'm missing. I couldn't find any.

So if I understand correctly, the magic is that I need client-side JS code that calls msg.send (not node.send()?). Then if I understand what you are saying, this message will appear as an output from the template node that created the UI.
Is any of this documented anwhere?

You should have asked :wink:

Fantastic. That's exactly what I was looking for. many thanks.

What I don't understand with this example is how to use this with the regulate template node. I have payload which contains an array. I pass that to a template node to build an HTML table of all the records and I need a button in each row so the user can select the item to be processed. I understand that this example goes to the ui-template. If I just put it in the template it will get rendered as a test (in the first example (Click me to send a hello world).
Can this be done in a template node?

Csongor

I don't think you need a standard template node for that. Use an ng-repeat in the ui-template node to build the table then just send the msg with the array on the payload.

I never used ng-repeat before, but I am getting there. I got this:

<style>
tr:nth-child(even) {background: #cce6ff; vertical-align: text-top; border-bottom: 1px solid #6699ff;}
tr:nth-child(odd) {background: #fffff; vertical-align: text-top; border-bottom: 1px solid #6699ff;}
</style>
<div height="250" style="height: 250px;">
<table>
    <tr><th>Time</th><th>Title</th><th>Description</th><th>Action</th></tr>
        <tr ng-repeat="row in msg.payload">
            <td style="white-space: nowrap">{{row.peTime}}</td>
            <td style="white-space: nowrap">{{row.peTitle}}</td>
            <td>{{row.peLong}}</td>
            <td><md-button ng-click="send({payload: row.peTime});">Click me</md-button>
            </td>
        </tr>
</table>
</div>

It displays the results just fine. When I click on the first "Click Me" it is OK. And I keep clicking, "selecting" more line, and after some time, the text from the table disappear and after the entire table collapses and disappears from the screen.
What have I done wrong? Is this related to the comment further up about making sure that the UI elements are unique?

Csongor

Well, I can't see anything wrong with that. It looks OK to me.

No, you've avoided that problem by using the repeat and calling send directly, you have no need of an ID.

You should open your browser's developer console and see if there are any errors happening. If not, try tracking the memory use because that behaviour strikes me as a memory leak leading to a crash.

OK, this is weird. With the debug console open I got errors that pointed tothis error reference on AngularJS.
So I changed to this:

<tr ng-repeat="row in msg.payload track by $index">

And also for testing to this:

<md-button ng-click="send({payload: $index});">Click me</md-button>

Now, when I click on the button, I get the message with the index in the payload, the entire table content disappears in Chrome and there are no errors in the console at all. Nothing in the node-red-log either.
How do I go further on this?

I was running into the same scenario. A message sent from template node would essentially delete my table. I was using scope.send is the only difference. I never could figure out why and used the ui-table node instead.

Sorry, I no longer use Angular as I found it a pain in the you-know-what.

I only use Dashboard for simple things now. I use uibuilder with VueJS when I want more complex ui's.

Hi what version of dashboard are you running?
I've just tested with a data set I use to create a set of dynamic widgets using ng-repeat.
Works fine no diapering table!

Agree with Julian that Angular is a pain.
I call it Anger-lar as shout at it so often.
That said I've been able to create complex UIs with dashboard node.

2 Likes