UI Template Edit msg.payload then Output

I'm making a dashboard UI table.

I wanted to achieve the msg.payload can be updated from the ui-template then output to other nodes.

Is there any thing I could add to make this happen?

 <body>
 <table>
     <tr>
       <th>Machine</th>
       <th>Target Time</th>
       <th>Quantity</th>
       <th>
         <input type="checkbox" ng-model="all">
         Reset
       </th>
     </tr>
     <tr ng-repeat="machine in msg.payload.factory">
       <td>{{machine.name}}</td>
       <td contenteditable>{{machine.min}}</td>
       <td contenteditable>{{machine.max}}</td>
       <td>
         <input type="checkbox" ng-checked="all">
       </td>
     </tr>
   </table>
   <md-button ng-model="msg.payload" ng-click="send(msg)">
     Submit
   </md-button>
   <p>{{msg.payload}}</p>
   </div>
 </body>

This are the data that passed to the template

 msg.payload = {
   factory: {
     machine00: {
       min: 1,
       max: 1,
       reset: false,
       name: "MC-TM-01"
     },
     machine01: {
       min: 1,
       max: 1,
       reset: false,
       name: "MC-TM-02"
     }
   }
 }

Not really enough info to make any full suggestions, I.e all payload or a row or a cell.

You may want to look at ui-table (Based on tabulator 4.7), or even tabulator library Documentation | Tabulator.

I've done the table part already,

What I needed is after the original payload is passed to the table,
It could be edited from the table and output the whole edited payload by pressing the submit button

Used the etable before, but the tick box requires 2 clicks to change it thus I tried to make the custom table

You are reinventing the wheel.

Ui-table will allow you to edit the cells of the table , once edited click row to send update
here is an example

[{"id":"54197d9fec778b15","type":"inject","z":"36348c32365b6b66","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"id\":0,\"machine\":\"aa-bb-11\",\"targetTime\":12,\"quantity\":3,\"reset\":false},{\"id\":1,\"machine\":\"aa-bb-12\",\"targetTime\":12,\"quantity\":3,\"reset\":false}]","payloadType":"json","x":970,"y":240,"wires":[["e60166842e8e4533"]]},{"id":"e60166842e8e4533","type":"function","z":"36348c32365b6b66","name":"Format for Table","func":"let table = flow.get(\"table\") ||  [];\nif(table.length < 1){\n    let ui_control = {\n        \"tabulator\": {\n            pagination:\"local\",\n            paginationSize:8,\n            paginationButtonCount:5,\n            selectable:1,\n            locale:true,\n            layout:\"fitColumns\",\n            columns:[\n                {\n                    title:\"Machine\", \n                    field:\"machine\",\n                    formatter: \"plaintext\", \n                    editor:\"input\",\n                    mask:\"AA-AA-99\",\n                    maskAutoFill:true, \n                    editorParams:{\n                        elementAttributes:{\n                            maxlength:\"8\", //set the maximum character length of the textarea element to 10 characters\n                        }\n                    }\n                },\n                {\n                    title:\"Target Time\", \n                    field:\"targetTime\",\n                    formatter: \"plaintext\", \n                    editor:\"input\", \n                    editorParams:{\n                        elementAttributes:{\n                            maxlength:\"10\", //set the maximum character length of the textarea element to 10 characters\n                        },\n                    mask:\"9999999999\"\n                    }\n                },\n                {\n                    title:\"Qyantity\", \n                    field:\"quantity\",\n                    formatter: \"plaintext\",\n                    editor:\"input\", \n                    editorParams:{\n                        elementAttributes:{\n                            maxlength:\"4\", //set the maximum character length of the textarea element to 10 characters\n                        },\n                    mask:\"9999\"\n                    }\n                },\n                {\n                    title:\"reset\", \n                    field:\"reset\", \n                    formatter:\"tickCross\",\n                    editor:\"tickCross\"\n                }\n            ]                  \n        }\n    }\nnode.send({ui_control}) \n}\nflow.set(\"table\",msg.payload)\nmsg.payload = {\n    command:\"replaceData\",\n    arguments:[msg.payload]\n}\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1180,"y":240,"wires":[["828a8f6f187a9559"]]},{"id":"828a8f6f187a9559","type":"ui_table","z":"36348c32365b6b66","group":"6305d8128da6cbab","name":"","order":1,"width":"17","height":"6","columns":[],"outputs":1,"cts":true,"x":1350,"y":240,"wires":[["461a02ef6c2ad5de"]]},{"id":"461a02ef6c2ad5de","type":"change","z":"36348c32365b6b66","name":"","rules":[{"t":"set","p":"table[msg.row]","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1550,"y":240,"wires":[[]]},{"id":"fbaf2bcb6253dc30","type":"ui_button","z":"36348c32365b6b66","name":"","group":"6305d8128da6cbab","order":2,"width":0,"height":0,"passthru":false,"label":"gettable data","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"getdata","topicType":"str","x":990,"y":300,"wires":[["b94e9f024fe1b1b2"]]},{"id":"b94e9f024fe1b1b2","type":"change","z":"36348c32365b6b66","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"table","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":1180,"y":300,"wires":[["402f38eb0fa3350b"]]},{"id":"402f38eb0fa3350b","type":"debug","z":"36348c32365b6b66","name":"debug 2475","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1370,"y":300,"wires":[]},{"id":"6305d8128da6cbab","type":"ui_group","name":"Group 1","tab":"b927390ff1bafb51","order":1,"disp":true,"width":17},{"id":"b927390ff1bafb51","type":"ui_tab","name":"bridge","icon":"dashboard","order":20,"disabled":false,"hidden":false}]

Base on Tabulator 4.7, but you could get more functionality by using tabulate 5+ direct in the template Or try dashboard 2 tables.

Oh two clicks, that must be a deal breaker, Have you tried adding a html check box.

To do it in ui-template node you would have to add text inputs to each td, then use ng-model, ng-blur and ng-value to send the row and property and changed data, and update the stored data.
e.g.

[{"id":"17f84e1550b7a06c","type":"ui_button","z":"36348c32365b6b66","name":"","group":"6305d8128da6cbab","order":2,"width":0,"height":0,"passthru":false,"label":"set data","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"topic","topicType":"msg","x":1180,"y":180,"wires":[["5c135f0b481561db"]]},{"id":"fbaf2bcb6253dc30","type":"ui_button","z":"36348c32365b6b66","name":"","group":"6305d8128da6cbab","order":2,"width":0,"height":0,"passthru":false,"label":"gettable data","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"getdata","topicType":"str","x":990,"y":300,"wires":[["b94e9f024fe1b1b2"]]},{"id":"b94e9f024fe1b1b2","type":"change","z":"36348c32365b6b66","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"table","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":1340,"y":300,"wires":[["402f38eb0fa3350b","797f37eb7bafc6f0"]]},{"id":"402f38eb0fa3350b","type":"debug","z":"36348c32365b6b66","name":"debug 2475","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1670,"y":300,"wires":[]},{"id":"797f37eb7bafc6f0","type":"json","z":"36348c32365b6b66","name":"","property":"payload","action":"","pretty":true,"x":1330,"y":360,"wires":[["cd459f1561f51e88"]]},{"id":"cd459f1561f51e88","type":"ui_text","z":"36348c32365b6b66","group":"6305d8128da6cbab","order":3,"width":"17","height":"4","name":"","label":"","format":"<pre>{{msg.payload}}</pre>","layout":"row-spread","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":1470,"y":360,"wires":[]},{"id":"461a02ef6c2ad5de","type":"change","z":"36348c32365b6b66","name":"","rules":[{"t":"set","p":"table[msg.id][msg.prop]","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1730,"y":240,"wires":[[]]},{"id":"bb259756667c55d0","type":"ui_template","z":"36348c32365b6b66","group":"6305d8128da6cbab","name":"","order":2,"width":0,"height":0,"format":"<table>\n    <tr ng-repeat=\"row in msg.payload\">\n        <td><input \n            ng-model=\"machineRow\"\n            ng-value=\"row.machine\"\n            ng-blur=\"send({payload:(machineRow||row.machine),id:row.id,prop:'machine'})\" \n            type=\"text\"              \n            required minlength=\"8\" \n            maxlength=\"8\" \n            size=\"10\"\n        /></td>\n    </tr>\n</table>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":1460,"y":240,"wires":[["461a02ef6c2ad5de"]]},{"id":"5c135f0b481561db","type":"change","z":"36348c32365b6b66","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"[{\"id\":0,\"machine\":\"aa-bb-11\",\"targetTime\":12,\"quantity\":3,\"reset\":false},{\"id\":1,\"machine\":\"aa-bb-12\",\"targetTime\":12,\"quantity\":3,\"reset\":false}]","tot":"json"},{"t":"set","p":"table","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1280,"y":240,"wires":[["bb259756667c55d0"]]},{"id":"6305d8128da6cbab","type":"ui_group","name":"Group 1","tab":"b927390ff1bafb51","order":1,"disp":true,"width":17},{"id":"b927390ff1bafb51","type":"ui_tab","name":"bridge","icon":"dashboard","order":20,"disabled":false,"hidden":false}]

Another fine solution from @E1cid -- above and beyond the initial request... thanks for all of your well-thought out answers!

Are all of these flows captured somewhere that the rest of this community can search later, when we run into similar questions? I dare say that I'll probably never be able to find this one-line flow if/when I need it -- there is just too much conversation text to read through to be "searchable", at least for me.

So is there a gist somewhere, or an entry in the flows library, where I can find the same sample flow? Thanks again.
__
Steve

You can bookmark posts

image

You can also add entries to the flows lib yourself. I have done this and know where to find all my entries really easily (I click my avatar after logging into the flows lib)

I realise thats sounds a little like a RTM response but it is actually better for your own organisation than having to search everyone's flows on the flows lib.

Thank you for you kind words.

I do tend to keep copies of them locally. Maybe I should add then to my git, I am pretty bad at doing that. Or may be give the examples a good title in the post, so easier to search

Just for info here is another example

Edit ui-template table and store data locally using localStorage, with command to get updated table

[{"id":"17f84e1550b7a06c","type":"ui_button","z":"36348c32365b6b66","name":"","group":"6305d8128da6cbab","order":2,"width":0,"height":0,"passthru":false,"label":"set data","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"[]","payloadType":"json","topic":"topic","topicType":"msg","x":1180,"y":180,"wires":[["5c135f0b481561db"]]},{"id":"5c135f0b481561db","type":"change","z":"36348c32365b6b66","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"[{\"id\":0,\"machine\":\"aa-bb-11\",\"targetTime\":12,\"quantity\":3,\"reset\":false},{\"id\":1,\"machine\":\"aa-bb-12\",\"targetTime\":12,\"quantity\":3,\"reset\":false}]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":1280,"y":240,"wires":[["bb259756667c55d0"]]},{"id":"bb259756667c55d0","type":"ui_template","z":"36348c32365b6b66","group":"6305d8128da6cbab","name":"","order":2,"width":0,"height":0,"format":"<table>\n    <tr ng-repeat=\"row in msg.payload\">\n        <td><input \n            ng-model=\"machine\"\n            ng-value=\"row.machine\"\n            ng-blur=\"send_row_data($index,'machine',(machine||row.machine))\" \n            type=\"text\"              \n            required minlength=\"8\" \n            maxlength=\"8\" \n            size=\"10\"\n        /></td>\n    </tr>\n</table>\n<script>\n(function(scope) {\n    scope.send_row_data = function (id, prop, payload) { \n        let stored = localStorage.getItem(\"table\");\n        let obj_stored = JSON.parse(stored);\n        if(obj_stored[id][prop]){\n            obj_stored[id][prop] = payload;\n            localStorage.setItem(\"table\", JSON.stringify(obj_stored));\n        }\n        //scope.send({payload,id,prop});    \n    }\n    scope.$watch('msg', function(msg) {\n        if ( msg.payload && Array.isArray(msg.payload) && msg.payload.length > 0 ) {\n            //alert(\"set\");\n            localStorage.setItem(\"table\", JSON.stringify(msg.payload));\n            //alert(localStorage.getItem(\"table\"))\n        }else if(msg.payload && msg.payload === \"output\"){\n            //alert(\"get\")\n            let output = localStorage.getItem(\"table\");\n            scope.send({payload:JSON.parse(output)});\n        }\n    })\n})(scope);\n</script>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","className":"","x":1460,"y":240,"wires":[["402f38eb0fa3350b","797f37eb7bafc6f0"]]},{"id":"fbaf2bcb6253dc30","type":"ui_button","z":"36348c32365b6b66","name":"","group":"6305d8128da6cbab","order":2,"width":0,"height":0,"passthru":false,"label":"gettable data","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"output","payloadType":"str","topic":"getdata","topicType":"str","x":1110,"y":300,"wires":[["bb259756667c55d0"]]},{"id":"402f38eb0fa3350b","type":"debug","z":"36348c32365b6b66","name":"debug 2475","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1650,"y":240,"wires":[]},{"id":"797f37eb7bafc6f0","type":"json","z":"36348c32365b6b66","name":"","property":"payload","action":"","pretty":true,"x":1330,"y":360,"wires":[["cd459f1561f51e88"]]},{"id":"cd459f1561f51e88","type":"ui_text","z":"36348c32365b6b66","group":"6305d8128da6cbab","order":3,"width":"17","height":"4","name":"","label":"","format":"<pre>{{msg.payload}}</pre>","layout":"row-spread","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":1470,"y":360,"wires":[]},{"id":"6305d8128da6cbab","type":"ui_group","name":"Group 1","tab":"b927390ff1bafb51","order":1,"disp":true,"width":17},{"id":"b927390ff1bafb51","type":"ui_tab","name":"bridge","icon":"dashboard","order":20,"disabled":false,"hidden":false}]

Yep, I do this as well... so I guess my question is more meant to open a dialog around the best way to capture these ad-hoc samples into a re-usable sample library.

Not pointing fingers here, because I do the same thing! I have all of these great (imo) flow samples running... well, somewhere... on one of my dozens of node-red installs locally or in the cloud. Seems there is never enough time to actually organize them and put the finishing documentation on them. A year later I have trouble finding them -- I guess I was hoping others have worked out a better way to manage their flows (to supplement the flows library).

Lets not hijack this thread, I think it best to open that question up on its own topic.

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