UI-Template Node Dynamic Buttons

I need a set of dynamic buttons, each button will have a name from a msg input array. Clicking any button will provide an output of that button's name. The names and number of buttons will be dynamic based on the input array of names.

I am using the ui_template node to build buttons. This part works. I need help to fix the code to output the button's name when clicked.

Here is my test flow so far:

[
    {
        "id": "cd92469bacae86bb",
        "type": "inject",
        "z": "4e84556f7bdfde3f",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "[\"Alan\",\"Gaye\",\"Fred\"]",
        "payloadType": "json",
        "x": 860,
        "y": 1340,
        "wires": [
            [
                "c910ae5a503fa8a9"
            ]
        ]
    },
    {
        "id": "c910ae5a503fa8a9",
        "type": "ui_template",
        "z": "4e84556f7bdfde3f",
        "group": "f9fbe54339c329ea",
        "name": "",
        "order": 1,
        "width": "6",
        "height": "1",
        "format": "\n\n<div>\n    <button ng-repeat=\"name in msg.payload\" ng-click=\"sendName(name)\">{{name}}</button>\n</div>\n\n<script>\n    (function(scope) {\n        scope.sendName = function(name) {\n            var message = {\n                payload: name\n            };\n            return message;\n        };\n    })(scope);\n</script>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 1140,
        "y": 1340,
        "wires": [
            [
                "2556190649c2e7ee"
            ]
        ]
    },
    {
        "id": "2556190649c2e7ee",
        "type": "debug",
        "z": "4e84556f7bdfde3f",
        "name": "debug 333",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1330,
        "y": 1340,
        "wires": []
    },
    {
        "id": "f9fbe54339c329ea",
        "type": "ui_group",
        "name": "Group 1",
        "tab": "c7c16878223e2d99",
        "order": 1,
        "disp": true,
        "width": 6
    },
    {
        "id": "c7c16878223e2d99",
        "type": "ui_tab",
        "name": "Test Dashboard",
        "icon": "dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

Alan

As you are calling a function from ng-click, in the function is where you need to send the msg.

<div>
    <button ng-repeat="name in msg.payload" ng-click="sendName(name)">{{name}}</button>
</div>
<script>
    (function(scope) {
        scope.sendName = function(name) {
            var message = {
                payload: name
            };
            scope.send(message);
        };
    })(scope);
</script>

Thanks,E1cid.

Here is the Dashboard. All good.

Screenshot 2023-09-03 at 9.41.24 AM

And, when I click on the Alan Button, msg.payload looks good:

But......This is what I now see on the Dashboard. Seems I did not apply the "ng-repeat" correctly for building the buttons from the names array, allowing it to run again, when a button is clicked on......

Help again please.

Screenshot 2023-09-03 at 9.48.14 AM

Below is the revised code.

Alan

[
    {
        "id": "7818c08f0d04a00a",
        "type": "inject",
        "z": "4e84556f7bdfde3f",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "[\"Alan\",\"Gaye\",\"Fred\"]",
        "payloadType": "json",
        "x": 900,
        "y": 1620,
        "wires": [
            [
                "9320f86d05c14296"
            ]
        ]
    },
    {
        "id": "9320f86d05c14296",
        "type": "ui_template",
        "z": "4e84556f7bdfde3f",
        "group": "f9fbe54339c329ea",
        "name": "",
        "order": 1,
        "width": "6",
        "height": "1",
        "format": "\n\n<div>\n    <button ng-repeat=\"name in msg.payload\" ng-click=\"sendName(name)\">{{name}}</button>\n</div>\n<script>\n    (function(scope) {\n        scope.sendName = function(name) {\n            var message = {\n                payload: name\n            };\n            scope.send(message);\n        };\n    })(scope);\n</script>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 1180,
        "y": 1620,
        "wires": [
            [
                "1a4fa3003caec3d1"
            ]
        ]
    },
    {
        "id": "1a4fa3003caec3d1",
        "type": "debug",
        "z": "4e84556f7bdfde3f",
        "name": "debug 333",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1370,
        "y": 1620,
        "wires": []
    },
    {
        "id": "f9fbe54339c329ea",
        "type": "ui_group",
        "name": "Group 1",
        "tab": "c7c16878223e2d99",
        "order": 1,
        "disp": true,
        "width": 6
    },
    {
        "id": "c7c16878223e2d99",
        "type": "ui_tab",
        "name": "Test Dashboard",
        "icon": "dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

I found a "hack" solution, please comment if there is a better way.

I found I could resend the name array, after a button click, to restore the buttons.

So, I built a filter to only allow a message to flow if it was in the name array. I used this to trigger a Change Node, to resend the Name Array to the ui-template node.

It works, but there must be a better way to handle this within the ui_node script??

Below is the code.

Alan

=============

[
    {
        "id": "d58da13902bab3ee",
        "type": "inject",
        "z": "3939c95af91dae0c",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "[\"Alan\",\"Gaye\",\"Fred\"]",
        "payloadType": "json",
        "x": 340,
        "y": 260,
        "wires": [
            [
                "e9d87b32705dcc3f",
                "7b6c59aa380e657b"
            ]
        ]
    },
    {
        "id": "e9d87b32705dcc3f",
        "type": "ui_template",
        "z": "3939c95af91dae0c",
        "group": "f9fbe54339c329ea",
        "name": "",
        "order": 1,
        "width": "6",
        "height": "1",
        "format": "\n\n<div>\n    <button ng-repeat=\"name in msg.payload\" ng-click=\"sendName(name)\">{{name}}</button>\n</div>\n<script>\n    (function(scope) {\n        scope.sendName = function(name) {\n            var message = {\n                payload: name\n            };\n            scope.send(message);\n        };\n    })(scope);\n</script>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 620,
        "y": 260,
        "wires": [
            [
                "9ebea481b78fc7b0"
            ]
        ]
    },
    {
        "id": "c9bfd1d96b058d73",
        "type": "change",
        "z": "3939c95af91dae0c",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "[\"Alan\",\"Gaye\",\"Fred\"]",
                "tot": "json"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 700,
        "y": 380,
        "wires": [
            [
                "e9d87b32705dcc3f"
            ]
        ]
    },
    {
        "id": "7b6c59aa380e657b",
        "type": "change",
        "z": "3939c95af91dae0c",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "names",
                "pt": "flow",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 620,
        "y": 180,
        "wires": [
            []
        ]
    },
    {
        "id": "9ebea481b78fc7b0",
        "type": "function",
        "z": "3939c95af91dae0c",
        "name": "name filter",
        "func": "\nvar allowedNames = flow.get(\"names\") || []; // Get the array of names from flow context\n\n// Function to filter messages\nfunction filterMessages(msg) {\n    if (allowedNames.includes(msg.payload)) {\n        return msg; // Message is allowed\n    } else {\n        return null; // Message is not allowed\n    }\n}\n\n// Check if the incoming message is allowed\nif (msg.hasOwnProperty(\"payload\")) {\n    msg = filterMessages(msg);\n}\n\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 810,
        "y": 260,
        "wires": [
            [
                "c9bfd1d96b058d73",
                "3f16721a7df0d16f"
            ]
        ]
    },
    {
        "id": "3f16721a7df0d16f",
        "type": "debug",
        "z": "3939c95af91dae0c",
        "name": "debug 335",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1020,
        "y": 260,
        "wires": []
    },
    {
        "id": "f9fbe54339c329ea",
        "type": "ui_group",
        "name": "Group 1",
        "tab": "c7c16878223e2d99",
        "order": 1,
        "disp": true,
        "width": 6
    },
    {
        "id": "c7c16878223e2d99",
        "type": "ui_tab",
        "name": "Test Dashboard",
        "icon": "dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

No need for hack
uncheck
Pass through messages from input.
and
Add output messages to stored state.
In the ui-tmemplate node.

Thanks again, E1cid

All good now. Works perfect.

Alan

Resolved

For others, here is the final, working flow:

Alan

[
    {
        "id": "87e9015f7b5f02a3",
        "type": "change",
        "z": "4e84556f7bdfde3f",
        "name": "Names",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "[\"Alan\",\"Gaye\",\"Fred\",\"Alice\"]",
                "tot": "json"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 650,
        "y": 2140,
        "wires": [
            [
                "d22016b0ba6c50e7"
            ]
        ]
    },
    {
        "id": "a1b89c895261f15a",
        "type": "debug",
        "z": "4e84556f7bdfde3f",
        "name": "debug 338",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1070,
        "y": 2140,
        "wires": []
    },
    {
        "id": "d70a982d45a12ba9",
        "type": "inject",
        "z": "4e84556f7bdfde3f",
        "name": "Trigger",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "trigger",
        "payloadType": "str",
        "x": 470,
        "y": 2140,
        "wires": [
            [
                "87e9015f7b5f02a3"
            ]
        ]
    },
    {
        "id": "d22016b0ba6c50e7",
        "type": "ui_template",
        "z": "4e84556f7bdfde3f",
        "group": "5617ace49257c9c0",
        "name": "",
        "order": 1,
        "width": "3",
        "height": "6",
        "format": "<div style=\"display: flex; flex-direction: column; align-items: center;\">\n    <button ng-repeat=\"name in msg.payload\" ng-click=\"sendName(name)\"\n            style=\"margin-bottom: 10px; width: 150px; height: 50px; font-size: 30px; color: red;\n                   background-color: yellow; border-radius: 10px;\">\n        {{name}}\n    </button>\n</div>\n<script>\n    (function(scope) {\n        scope.sendName = function(name) {\n            var message = {\n                payload: name\n            };\n            scope.send(message);\n        };\n    })(scope);\n</script>",
        "storeOutMessages": false,
        "fwdInMessages": false,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 880,
        "y": 2140,
        "wires": [
            [
                "a1b89c895261f15a"
            ]
        ]
    },
    {
        "id": "5617ace49257c9c0",
        "type": "ui_group",
        "name": "Group 2",
        "tab": "c7c16878223e2d99",
        "order": 2,
        "disp": true,
        "width": "3",
        "collapse": false,
        "className": ""
    },
    {
        "id": "c7c16878223e2d99",
        "type": "ui_tab",
        "name": "Test Dashboard",
        "icon": "dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

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