Add text to ui template based on javascrip function

Hi there!

Is there any way it is possible to modify the ui template based on a function node?

For example: I right now have one button
Skærmbillede 2022-09-09 184950

Is there any way I can create i.e. a number of buttons based on i.e. the length of an array?
Just to specify: I know I can create i.e. tree buttons by modifying the ui template directly. Question is if I dynamically can change the ui template node based on variables in the flow which changes over time.
In other words, is there any way I can let users create their own UI elements such as adding a button.

Thanks in advance

You can use javascript to create a dynamic html template which would be your <button> tags and feed that into ui-template using msg.template.

Or you could us angular ng-repeat to take an object and create a button for each property and value.

Angular example

[{"id":"443f758e.84052c","type":"inject","z":"30af2d3e.d94ea2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"one\":0,\"two\":1}","payloadType":"json","x":210,"y":2520,"wires":[["4daf7883.0e1478"]]},{"id":"4daf7883.0e1478","type":"ui_template","z":"30af2d3e.d94ea2","group":"2d4fe667.28f8ba","name":"","order":11,"width":0,"height":0,"format":"<div ng-repeat=\"(key, value) in msg.payload\">\n    <div >\n    <md-button  ng-click='send({payload:value});'>{{key}}</md-button>\n    </div>\n</div>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":430,"y":2520,"wires":[["b616a8e5.23cfd"]]},{"id":"b616a8e5.23cfd","type":"debug","z":"30af2d3e.d94ea2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":670,"y":2520,"wires":[]},{"id":"2d4fe667.28f8ba","type":"ui_group","name":"demo","tab":"1caa8458.b17814","order":1,"disp":true,"width":"12","collapse":false},{"id":"1caa8458.b17814","type":"ui_tab","name":"Demo","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Thank you, the ng-repeat approach works very nicely. I want to create two rows of buttons next to each other. When button "one" is added, I want button "a" to be added to the right. Do you by any change have an idea of how I can do this?

I managed to get two lines, but not quite how I want it (button "one" should be right next to button "a")

Flow:

 [
    {
        "id": "8c2a0203fdc14ff3",
        "type": "inject",
        "z": "456eac4678ecd5a9",
        "name": "",
        "props": [
            {
                "p": "numbers",
                "v": "{\"one\":0,\"two\":1,\"three\":0,\"four\":1,\"five\":0,\"six\":1,\"seven\":0,\"eight\":1}",
                "vt": "json"
            },
            {
                "p": "letters",
                "v": "{\"a\":0,\"b\":1,\"c\":0,\"d\":1,\"e\":0,\"f\":1,\"g\":0,\"h\":1}",
                "vt": "json"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 270,
        "y": 900,
        "wires": [
            [
                "2ed67a7a6ce06d55"
            ]
        ]
    },
    {
        "id": "2ed67a7a6ce06d55",
        "type": "ui_template",
        "z": "456eac4678ecd5a9",
        "group": "2d4fe667.28f8ba",
        "name": "",
        "order": 2,
        "width": 6,
        "height": 17,
        "format": "<div ng-repeat=\"(key, value) in msg.numbers\">\n    <div >\n    <button type=\"button\" ng-click='send({payload:value});' class=\"buttonLeft\">{{key}}</button>\n    </div>\n</div>\n\n<div ng-repeat=\"(key, value) in msg.letters\">\n    <div >\n    <button type=\"button\" ng-click='send({payload:value});' class=\"buttonRight\">{{key}}</button>\n    </div>\n</div>\n\n<style>\n    .buttonLeft {\n      background-color: rgba(51, 51, 51, 0.05);\n      border-radius: 8px;\n      border-width: 0;\n      color: #333333;\n      cursor: pointer;\n      display: inline-block;\n      font-family: \"Haas Grot Text R Web\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n      font-size: 14px;\n      font-weight: 500;\n      line-height: 20px;\n      list-style: none;\n      margin: 0;\n      padding: 10px 12px;\n      text-align: center;\n      transition: all 200ms;\n      vertical-align: baseline;\n      white-space: nowrap;\n      user-select: none;\n      margin-top: 1.5px;\n      margin-bottom: 1.5px;\n      width: 100px;\n      height: 40px;\n      box-shadow: -1.5px 2.5px #e0e0e0;\n      -webkit-user-select: none;\n      touch-action: manipulation;\n        }\n        \n    .buttonRight {\n      background-color: rgba(51, 51, 51, 0.05);\n      border-radius: 8px;\n      border-width: 0;\n      color: #333333;\n      cursor: pointer;\n      display: inline-block;\n      font-family: \"Haas Grot Text R Web\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n      font-size: 14px;\n      font-weight: 500;\n      line-height: 20px;\n      list-style: none;\n      margin: 0;\n      padding: 10px 12px;\n      text-align: center;\n      transition: all 200ms;\n      vertical-align: baseline;\n      white-space: nowrap;\n      user-select: none;\n      margin-top: 1.5px;\n      margin-bottom: 1.5px;\n      width: 100px;\n      height: 40px;\n      box-shadow: -1.5px 2.5px #e0e0e0;\n      float:right;\n      -webkit-user-select: none;\n      touch-action: manipulation;\n             \n        }\n</style>\n\n",
        "storeOutMessages": false,
        "fwdInMessages": false,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 520,
        "y": 900,
        "wires": [
            [
                "739546fdac257049"
            ]
        ]
    },
    {
        "id": "739546fdac257049",
        "type": "debug",
        "z": "456eac4678ecd5a9",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 760,
        "y": 900,
        "wires": []
    },
    {
        "id": "2d4fe667.28f8ba",
        "type": "ui_group",
        "name": "demo",
        "tab": "1caa8458.b17814",
        "order": 1,
        "disp": true,
        "width": 6,
        "collapse": false
    },
    {
        "id": "1caa8458.b17814",
        "type": "ui_tab",
        "name": "Demo",
        "icon": "dashboard",
        "order": 4,
        "disabled": false,
        "hidden": false
    }
]

You would add css classes to elements then style as you wish. Needs more work but this should get you going.

<style>
.buttonrow { 
    width: 90%; 
} 
.buttoncolumn { 
    float: left; 
    width: 50%; 
} 

</style>
<div class="buttonrow">
<div class="buttoncolumn" ng-repeat="(key, value) in msg.payload">
    <md-button  ng-click='send({payload:value});'>{{key}}</md-button>
    </div>
</div>

Thank you, I've been playing around with it for a little.
Basically, i managed to get the payload object looking like this (which is almost what I want):

The example above only takes one payload (msg.payload) though. Is there a way it is possible for me to get the left group of buttons to display i.e. msg.numbers (containing an object with numbers) and the right column to display i.e. msg.letters (containing an object with letters).

This is what I got currently:

[
    {
        "id": "42c59e1284dedd08",
        "type": "ui_template",
        "z": "9b7a0b92d8d0d4b8",
        "group": "2d4fe667.28f8ba",
        "name": "",
        "order": 1,
        "width": 6,
        "height": 8,
        "format": "<style>\n#button{\n    width: 148px;\n    font-size: 8px;\n    text-transform: capitalize;\n}\n.buttoncolumn { \n    float: left;\n    margin-left:4px;\n    margin-top: 2px;\n    margin-bottom: 2px;\n} \n</style>\n\n<div class=\"buttonrow\">\n<div class=\"buttoncolumn\" ng-repeat=\"(key, value) in msg.payload\">\n    <md-button  id = \"button\" ng-click='send({payload:value});'>{{key}}</md-button>\n    </div>\n</div>",
        "storeOutMessages": false,
        "fwdInMessages": false,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 820,
        "y": 820,
        "wires": [
            [
                "221bbc4b2f6bcc85"
            ]
        ]
    },
    {
        "id": "221bbc4b2f6bcc85",
        "type": "debug",
        "z": "9b7a0b92d8d0d4b8",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1010,
        "y": 820,
        "wires": []
    },
    {
        "id": "335bc92c6c8aa29b",
        "type": "inject",
        "z": "9b7a0b92d8d0d4b8",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{\"one\":0,\"two\":1,\"three\":2,\"four\":3,\"five\":4,\"six\":5,\"seven\":6,\"eight\":7}",
        "payloadType": "json",
        "x": 670,
        "y": 820,
        "wires": [
            [
                "42c59e1284dedd08"
            ]
        ]
    },
    {
        "id": "2d4fe667.28f8ba",
        "type": "ui_group",
        "name": "demo",
        "tab": "1caa8458.b17814",
        "order": 1,
        "disp": true,
        "width": 6,
        "collapse": false
    },
    {
        "id": "1caa8458.b17814",
        "type": "ui_tab",
        "name": "Demo",
        "icon": "dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

Basically, what I'm trying to create is the following:
Skærmbillede 2022-09-10 144955

You keep moving goal posts,
you can add as many properties as you to your payload and reference them in the template.

[{"id":"7fd9dc2b.f93f4c","type":"inject","z":"30af2d3e.d94ea2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"one\":{\"value\":0,\"display\":\"test1\"},\"two\":{\"value\":\"name2\",\"display\":\"test2\"},\"three\":{\"value\":2,\"display\":\"test3\"},\"four\":{\"value\":\"name4\",\"display\":\"test4\"}}","payloadType":"json","x":120,"y":3120,"wires":[["37b0f749.79e768"]]},{"id":"37b0f749.79e768","type":"ui_template","z":"30af2d3e.d94ea2","group":"2d4fe667.28f8ba","name":"","order":1,"width":"12","height":"1","format":"<style>\n#button{\n    width: 148px;\n    font-size: 8px;\n    text-transform: capitalize;\n}\n\n.buttoncolumn { \n    float: left;\n    margin-left:4px;\n    margin-top: 2px;\n    margin-bottom: 2px;\n} \n</style>\n\n<div class=\"buttonrow\">\n<div class=\"buttoncolumn\" ng-repeat=\"(key, obj) in msg.payload\">\n    <md-button  id=\"button\" ng-click='send({payload: obj.value});'>{{obj.value}} {{obj.display}}</md-button>\n    </div>\n</div>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":270,"y":3120,"wires":[["130c1797.d6df18"]]},{"id":"130c1797.d6df18","type":"debug","z":"30af2d3e.d94ea2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":460,"y":3120,"wires":[]},{"id":"2d4fe667.28f8ba","type":"ui_group","name":"demo","tab":"1caa8458.b17814","order":1,"disp":true,"width":"12","collapse":false},{"id":"1caa8458.b17814","type":"ui_tab","name":"Demo","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

you can also use ng-if to display a button or not and you can feed back the output
e.g.

[{"id":"d87ab5e8.807fd8","type":"inject","z":"30af2d3e.d94ea2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"one\":0,\"two\":1}","payloadType":"json","x":180,"y":2440,"wires":[["10dbd46d.327854"]]},{"id":"10dbd46d.327854","type":"ui_template","z":"30af2d3e.d94ea2","group":"2d4fe667.28f8ba","name":"","order":11,"width":0,"height":0,"format":"<div ng-repeat=\"(key, value) in msg.payload\">\n    <div >\n    <md-button ng-if=\"value === 1\" ng-click='send({payload:{[key]:value}, data: msg.payload});'>{{key}}</md-button>\n    </div>\n    <div>\n    <md-button ng-if=\"value === 0\" ng-style=\"{'background-color':'green'}\" ng-click='send({payload:{[key]:value}, data: msg.payload});'>{{key}}</md-button>\n    </div>\n</div>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":400,"y":2440,"wires":[["729354e0.6e347c","ce2c94fa.67d7d"]]},{"id":"ce2c94fa.67d7d","type":"change","z":"30af2d3e.d94ea2","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"$merge([$$.data,{$keys($$.payload): $$.payload.* = 1 ? 0 : 1}])","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":2380,"wires":[["10dbd46d.327854"]]},{"id":"729354e0.6e347c","type":"debug","z":"30af2d3e.d94ea2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":640,"y":2440,"wires":[]},{"id":"2d4fe667.28f8ba","type":"ui_group","name":"demo","tab":"1caa8458.b17814","order":1,"disp":true,"width":"12","collapse":false},{"id":"1caa8458.b17814","type":"ui_tab","name":"Demo","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Thanks, sry for not being very specific in the beginning. Didn't want to bother if I could fix it easily. I tried with your method and it now almost works.

Only thing is I want to add a checkbox next to the left group of buttons (as on the previous picture). I added a number properti to my object which increases by one for each new object, like this:

I thought I maybe could use ng-if to only insert a checkbox next to i.e. every button with an even number property. I'm pretty sure this should be possible but my knowledge within this topic is pretty limited. This is what I tried, but it didn't work.

Again, thank you very much for your help so far. It has been very useful.

There is extensive documentation of this and plenty of search knowledge available.

You do not require {{ }} in the ng quote block, as you can see in the ng-click="" obj.value has no {{ }}.
There is also $index available which increments for each repeat, and $odd/$even and others. so you don't need to add your number property.

You're the best. Thanks a ton!

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