How to send a message out of ui_template using tabulator

Hi there!

Yes, I searched the forum for similar answer and did not find one - at least none that worked on my code.
In fact I took quite some inspiration from the ui_table node of @knolleary .

What I want to achieve is to send messages out of the ui_template. In that template I have inserted tabulator (latest version:5.4). the reason I do not use the ui_table node (anymore) is that I need a lot more functionality of tabulator that ui_table does not (yet?) gives access to.

This is the bare bone example of my issue:

[{"id":"b84fd2f0.2ecab","type":"tab","label":"Tabulator-Example","disabled":false,"info":""},{"id":"6c38b40a.49b5ec","type":"debug","z":"b84fd2f0.2ecab","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":910,"y":260,"wires":[]},{"id":"474bdcb4.3b7cc4","type":"ui_button","z":"b84fd2f0.2ecab","name":"get table data","group":"1bbe4d3.9a59cb3","order":9,"width":"4","height":"1","passthru":false,"label":"get table data","tooltip":"","color":"","bgcolor":"","icon":"save","payload":"{\"cmd\":\"getTableData\",\"arg\":\"\"}","payloadType":"json","topic":"","topicType":"str","x":340,"y":320,"wires":[["5a7106fb.ba3f58"]]},{"id":"88f06ecd.2f8c9","type":"inject","z":"b84fd2f0.2ecab","name":"trigger","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"cmd\":\"getLastId\",\"arg\":\"\"}","payloadType":"json","x":370,"y":260,"wires":[["5a7106fb.ba3f58"]]},{"id":"5a7106fb.ba3f58","type":"ui_template","z":"b84fd2f0.2ecab","group":"955ee4fa.99cfb8","name":"Tabulator","order":7,"width":"16","height":"8","format":"<div id=\"example-table2\"></div>\n<script>\n    var tabledata = [\n        {id:0, pos:0, age:\"1\"},\n        {id:1, pos:1, age:\"12\"},\n        {id:2, pos:2, age:\"1\"},\n        {id:3, pos:3, age:\"42\"},\n        {id:4, pos:4, age:\"11\"},\n    ];\n    \n    var table = new Tabulator(\"#example-table2\", {\n     \tdata:tabledata, //assign data to table\n     \tindex:\"id\",     // set the field which serves as index for tabulator\n     \tlayout:\"fitColumns\", //fit columns to width of table (optional)\n     \tcolumns:[ //Define Table Columns\n     \t    {title:\"ID\", field:\"id\", width:60},\n    \t \t{title:\"Position\", field:\"pos\", width:150},\n    \t \t{title:\"Age\", field:\"age\", hozAlign:\"left\", formatter:\"progress\",headerSort:false,cellClick:function(e,cell){\n    \t \t        this.send({payload:\"testcell\"});\n        \t \t}\n    \t \t}\n     \t]\n    });\n    \n    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n    // CUSTOM FUNCTIONS\n    function getLastTableIndex(myTable){\n        var last_id = Math.max.apply(Math, myTable.getRows().map(function(o) { return o.getIndex(); }));\n        if(!Number.isFinite(last_id)) last_id = -1;\n        \n        return last_id;\n    };\n    \n    \n    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n    // INTERACTION FUNCTIONS\n    //This is needed to interact with Node-Red when a message is sent to the ui-template.\n    (function(scope){\n        \n        // // TODO replace with code that does what you want ot happen everytime you click anywhere in a row\n        // table.on(\"rowClick\", function(e, row){ \n        // \tscope.send({payload:\"test\"});\n        // });\n        \n        scope.$watch('msg', function(msg){\n            if(msg){\n                //do something here when a message arrives like table.setData();\n                if(msg.hasOwnProperty(\"payload\")){\n                    if(msg.payload.hasOwnProperty(\"cmd\") && msg.payload.hasOwnProperty(\"arg\")){\n                        switch(msg.payload.cmd){\n                            case \"getTableData\":\n                                scope.send({payload:table.getData()});\n                                break;\n                            case \"getLastId\":\n                                scope.send({payload:getLastTableIndex(table)});\n                                break;\n                        }\n                    }\n                }\n            }\n        });\n        \n    })(scope);\n</script>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","x":680,"y":260,"wires":[["6c38b40a.49b5ec"]]},{"id":"7008b521.2c90bc","type":"ui_template","z":"b84fd2f0.2ecab","group":"d386fb82fa5ef195","name":"Header","order":6,"width":0,"height":0,"format":"<link href=\"https://unpkg.com/tabulator-tables/dist/css/tabulator_midnight.min.css\" rel=\"stylesheet\">\n<script type=\"text/javascript\" src=\"https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js\"></script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"global","x":680,"y":200,"wires":[[]]},{"id":"1bbe4d3.9a59cb3","type":"ui_group","name":"commands","tab":"752d9f37.ffa91","order":2,"disp":false,"width":"16","collapse":false},{"id":"955ee4fa.99cfb8","type":"ui_group","name":"table","tab":"752d9f37.ffa91","order":1,"disp":true,"width":"16","collapse":false},{"id":"d386fb82fa5ef195","type":"ui_group","name":"Tabulator Example","tab":"d0ef1a9bfa867de7","order":2,"disp":true,"width":"16","collapse":true},{"id":"752d9f37.ffa91","type":"ui_tab","name":"Tabulator_Example","icon":"fa-table","disabled":false,"hidden":false},{"id":"d0ef1a9bfa867de7","type":"ui_tab","name":"KnobConfig2","icon":"adjust","order":1,"disabled":false,"hidden":false}]

It works very well to receive a msg, act upon it and send a message back to node-red-
What does not work is the send function inside the cellClick-event of the 'age' column. The code I copied from the ui_table node. I also tried many other setups like putting the send function inside the (function(scope){ myFu(){scope.send()} }) and then use myFu in the cellclick event handler. No matter what I seem to not be able to properly access the send() function.
Am I missing something on how to define the table in the template in order to be able to access send()?

I am grateful for any pointer!
Cheers
JR

1 Like

One way to get scope.send() is to define the click handler inside the (function(scope){...})(scope) code:

<div id="example-table2"></div>
<script>
    var tabledata = [
        {id:0, pos:0, age:"1"},
        {id:1, pos:1, age:"12"},
        {id:2, pos:2, age:"1"},
        {id:3, pos:3, age:"42"},
        {id:4, pos:4, age:"11"},
    ];
    
    var table = new Tabulator("#example-table2", {
     	data:tabledata, //assign data to table
     	index:"id",     // set the field which serves as index for tabulator
     	layout:"fitColumns", //fit columns to width of table (optional)
     	columns:[ //Define Table Columns
     	    {title:"ID", field:"id", width:60},
    	 	{title:"Position", field:"pos", width:150},
    	 	{title:"Age", field:"age", hozAlign:"left", formatter:"progress",headerSort:false}
     	]
    });
    
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    // CUSTOM FUNCTIONS
    function getLastTableIndex(myTable){
        var last_id = Math.max.apply(Math, myTable.getRows().map(function(o) { return o.getIndex(); }));
        if(!Number.isFinite(last_id)) last_id = -1;
        
        return last_id;
    };
    
    
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    // INTERACTION FUNCTIONS
    //This is needed to interact with Node-Red when a message is sent to the ui-template.
    (function(scope){
        
        // // TODO replace with code that does what you want ot happen everytime you click anywhere in a row
        table.on("cellClick", function(e, cell){ 
         	scope.send({topic:"cellClick", payload:cell.getData()});
        });


        
        scope.$watch('msg', function(msg){
            if(msg){
                //do something here when a message arrives like table.setData();
                if(msg.hasOwnProperty("payload")){
                    if(msg.payload.hasOwnProperty("cmd") && msg.payload.hasOwnProperty("arg")){
                        switch(msg.payload.cmd){
                            case "getTableData":
                                scope.send({payload:table.getData()});
                                break;
                            case "getLastId":
                                scope.send({payload:getLastTableIndex(table)});
                                break;
                        }
                    }
                }
            }
        });
        
    })(scope);
</script>

Hi Knoepsche!
Does that mean that once I define the click handler, that I get scope.send() also in other sections of the code?
My target was to use the send funtion inside the tabulator event-handlers, like cellEdited.
How would I achieve that?
Thanks!

How about packing your whole code into the scope? This way you always get the scope from inside your table:

<div id="example-table2"></div>
<script>
    
    (function(scope){
    
    // // TODO replace with code that does what you want ot happen everytime you click anywhere in a row
    // table.on("rowClick", function(e, row){
    // scope.send({payload:"test"});
    // });
    
    scope.tabledata = [
        {id:0, pos:0, age:"1"},
        {id:1, pos:1, age:"12"},
        {id:2, pos:2, age:"1"},
        {id:3, pos:3, age:"42"},
        {id:4, pos:4, age:"11"},
    ];
    
    scope.table = new Tabulator("#example-table2", {
        data:scope.tabledata, //assign data to table
        index:"id", // set the field which serves as index for tabulator
        layout:"fitColumns", //fit columns to width of table (optional)
        columns:[ //Define Table Columns
            {title:"ID", field:"id", width:60},
            {title:"Position", field:"pos", width:150},
            {title:"Age", field:"age", hozAlign:"left",
            formatter:"progress",headerSort:false,cellClick:function(e,cell){scope.send({payload:"testcell"})}}
        ],
    });
    
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    // CUSTOM FUNCTIONS
    scope.getLastTableIndex = function(myTable){
        var last_id = Math.max.apply(Math, myTable.getRows().map(function(o) { return o.getIndex(); }));
        if(!Number.isFinite(last_id)) last_id = -1;
        return last_id;
    };
    
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    // INTERACTION FUNCTIONS
    //This is needed to interact with Node-Red when a message is sent to the ui-template.
    
        scope.$watch('msg', function(msg){
            if(msg){
                //do something here when a message arrives like table.setData();
                if(msg.hasOwnProperty("payload")){
                    if(msg.payload.hasOwnProperty("cmd") && msg.payload.hasOwnProperty("arg")){
                        switch(msg.payload.cmd){
                            case "getTableData":
                                scope.send({payload:scope.table.getData()});
                                break;
                            case "getLastId":
                                scope.send({payload:scope.getLastTableIndex(scope.table)});
                                break;
                        }
                    }
                }
            }
        });
        
    })(scope);
</script>
1 Like

Thank you so much!
I totally overlooked this simple approach.

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