Problem with tabulator.js in ui-template

I am using tabulator.js in a ui-template. This works perfectly in my example flow.

[
    {
        "id": "a361f3170fba9d32",
        "type": "ui_template",
        "z": "b5632267ab948d52",
        "group": "87e32ce83242e0f3",
        "name": "tabulator.js html/scr/css ",
        "order": 1,
        "width": 0,
        "height": 0,
        "format": "<link href=\"https://unpkg.com/tabulator-tables@5.4/dist/css/tabulator.min.css\" rel=\"stylesheet\">\n<script type=\"text/javascript\" src=\"https://unpkg.com/tabulator-tables@5.4/dist/js/tabulator.min.js\"></script>\n\n<!-- see http://tabulator.info/examples/5.4#theming \ndark: /dist/css/tabulator_midnight.min.css\nadjustable: /dist/css/tabulator.min.css\n//-->\n\n<div id=\"openWindowsTable\"></div>\n<script>\n    var table = new Tabulator(\"#openWindowsTable\",  {\n        height:\"700px\" ,\n        placeholder:\"Keine Daten verfügbar!\",\n        layout: \"fitDataStretch\",\n   \n        movableColumns: true,\n        /*allow column order to be changed*/\n        \n        /*colums format definitions*/\n        columns: [{\n            title: \"Fenster\",\n            field: \"window\",\n            width: 250\n            },\n            {\n            title: \"Status\",\n            field: \"status\",\n            formatter: function(cell, formatterParams, onRendered){\n                    //cell - the cell component\n                    //formatterParams - parameters set for the column\n                    //onRendered - function to call when the formatter has been rendered\n                    return \"<span style='color:Black; font-weight:bold;'>\" + cell.getValue() + \"</span>\"\n                },\n            },\n            {\n            title: \"Zeit\",\n            field: \"ts\",\n            },\n        ],\n         \n        columnDefaults:{ \n            tooltip:true,\n        },\n        \n        /*initial sorting */\n        initialSort:[\n            {column:\"status\", dir:\"desc\"}, //sort by this first\n            {column:\"ts\", dir:\"desc\"}, //then sort by this second\n        ],\n        \n        /* group by ort*/\n        groupBy: \"ort\",\n        groupStartOpen: true,\n\n        /* format groupHeader */\n        groupHeader: function(value, count, data, group) {\n            var r = \"<span style='color:#d00; margin-left:10px;'>(\" + count + \" Fenster)</span>\";\n            return value + r;\n        },\n        \n        /*format individal cell*/\n        rowFormatter: function(row) {\n            const cl = row.getCells();\n            cl[1].getElement().style.backgroundColor = (cl[1]._cell.value === 'open' ? '#F1948A' : '#82E0AA');\n        },\n    });\n\n    /* events */\n    \n    table.on(\"renderComplete\",function() {\n        let data = table.getData();\n        let groupHeaderList = document.querySelectorAll(\".tabulator-row.tabulator-group\");\n        let groups = Array.from(groupHeaderList, (group) => group.outerText.split('(')[0]);\n        \n        for (let i = 0; i < groups.length; i++) { const group=groups[i]; const statusOpen=data.some(g=> g.ort === group &&\n            g.status === 'open');\n            groupHeaderList[i].style.backgroundColor = (statusOpen) ? '#E74C3C' : '#2ECC71';\n        }\n    });\n\n      \n    table.on(\"tableBuilt\", function() {return console.log(\"from tableBuilt event\")});\n    \n    (function(scope) { \n        scope.$watch('msg', function(msg) {\n            if(msg) {\n                var tabledata = msg.payload;\n                table.replaceData(tabledata);\n                \n            }\n        });\n    })(scope);\n\n</script>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 650,
        "y": 400,
        "wires": [
            []
        ]
    },
    {
        "id": "6974f7f03a30f5fb",
        "type": "inject",
        "z": "b5632267ab948d52",
        "name": "Testdata",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "[\t   {\t       \"window\":\"Zwischentür_vorn\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 07:26:37\",\t       \"ort\":\"Aussen\"\t   },\t   {\t       \"window\":\"Zwischentür_Hof\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 07:26:36\",\t       \"ort\":\"Aussen\"\t   },\t   {\t       \"window\":\"Haustür\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 09:22:11\",\t       \"ort\":\"EG\"\t   },\t   {\t       \"window\":\"WG_Fenster_links\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 09:22:06\",\t       \"ort\":\"EG\"\t   },\t   {\t       \"window\":\"Büro_WGn\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 07:28:52\",\t       \"ort\":\"EG\"\t   },\t   {\t       \"window\":\"Fenster_Gäste_WC\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 06:53:09\",\t       \"ort\":\"EG\"\t   },\t   {\t       \"window\":\"WG_Schiebetuer\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 06:48:47\",\t       \"ort\":\"EG\"\t   },\t   {\t       \"window\":\"WGTuer\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 06:48:25\",\t       \"ort\":\"EG\"\t   },\t   {\t       \"window\":\"WG_Fenster_rechts\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 06:33:56\",\t       \"ort\":\"EG\"\t   },\t   {\t       \"window\":\"Wirtschaftsraum_Fenster\",\t       \"status\":\"closed\",\t       \"ts\":\"03.10.22 02:04:44\",\t       \"ort\":\"EG\"\t   },\t   {\t       \"window\":\"Kellerküche_Fenster\",\t       \"status\":\"open\",\t       \"ts\":\"30.09.22 11:16:50\",\t       \"ort\":\"Keller\"\t   },\t   {\t       \"window\":\"Sportraum_Fenster\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 08:34:12\",\t       \"ort\":\"Keller\"\t   },\t   {\t       \"window\":\"Billard_Fenster\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 08:33:57\",\t       \"ort\":\"Keller\"\t   },\t   {\t       \"window\":\"Vorratsraum_Fenster\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 08:33:38\",\t       \"ort\":\"Keller\"\t   },\t   {\t       \"window\":\"Keller\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 08:33:36\",\t       \"ort\":\"Keller\"\t   },\t   {\t       \"window\":\"EWerkstatt_Fenster\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 05:00:27\",\t       \"ort\":\"Keller\"\t   },\t   {\t       \"window\":\"Safe\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 04:36:26\",\t       \"ort\":\"Keller\"\t   },\t   {\t       \"window\":\"Schlafstube_Fenster_links\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 08:35:42\",\t       \"ort\":\"OG\"\t   },\t   {\t       \"window\":\"Schlafstube_Fenster_rechts\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 08:31:45\",\t       \"ort\":\"OG\"\t   },\t   {\t       \"window\":\"OG_Kinderzimmer_Fenster\",\t       \"status\":\"closed\",\t       \"ts\":\"09.10.22 02:51:01\",\t       \"ort\":\"OG\"\t   }\t]",
        "payloadType": "jsonata",
        "x": 400,
        "y": 400,
        "wires": [
            [
                "a361f3170fba9d32"
            ]
        ]
    },
    {
        "id": "87e32ce83242e0f3",
        "type": "ui_group",
        "name": "offene Fenster",
        "tab": "a96d3174521b3e8e",
        "order": 2,
        "disp": true,
        "width": 9,
        "collapse": true,
        "className": ""
    },
    {
        "id": "a96d3174521b3e8e",
        "type": "ui_tab",
        "name": "Listen ",
        "icon": "list",
        "disabled": false,
        "hidden": false
    }
]

In the production system the table is much bigger. This still works without problems, but I get a hint in the browser console:

[Warning] Table Not Initialized - Calling the replaceData function before the table is initialized may result in inconsistent behavior, Please wait for the tableBuilt event before calling this function. (ui, line 2)

Here is the code from the ui-template:

<link href="https://unpkg.com/tabulator-tables@5.4/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@5.4/dist/js/tabulator.min.js"></script>

<div id="openWindowsTable"></div>
<script>
    var table = new Tabulator("#openWindowsTable",  {
        height:"700px" ,
        placeholder:"Keine Daten verfügbar!",
        layout: "fitDataStretch",
   
        movableColumns: true,
        /*allow column order to be changed*/
        
        /*colums format definitions*/
        columns: [{
            title: "Fenster",
            field: "window",
            width: 250
            },
            {
            title: "Status",
            field: "status",
            formatter: function(cell, formatterParams, onRendered){
                    //cell - the cell component
                    //formatterParams - parameters set for the column
                    //onRendered - function to call when the formatter has been rendered
                    return "<span style='color:Black; font-weight:bold;'>" + cell.getValue() + "</span>"
                },
            },
            {
            title: "Zeit",
            field: "ts",
            },
        ],
         
        columnDefaults:{ 
            tooltip:true,
        },
        
        /*initial sorting */
        initialSort:[
            {column:"status", dir:"desc"}, //sort by this first
            {column:"ts", dir:"desc"}, //then sort by this second
        ],
        
        /* group by ort*/
        groupBy: "ort",
        groupStartOpen: true,

        /* format groupHeader */
        groupHeader: function(value, count, data, group) {
            var r = "<span style='color:#d00; margin-left:10px;'>(" + count + " Fenster)</span>";
            return value + r;
        },
        
        /*format individal cell*/
        rowFormatter: function(row) {
            const cl = row.getCells();
            cl[1].getElement().style.backgroundColor = (cl[1]._cell.value === 'open' ? '#F1948A' : '#82E0AA');
        },
    });

    /* events */
    
    table.on("renderComplete",function() {
        let data = table.getData();
        let groupHeaderList = document.querySelectorAll(".tabulator-row.tabulator-group");
        let groups = Array.from(groupHeaderList, (group) => group.outerText.split('(')[0]);
        
        for (let i = 0; i < groups.length; i++) { const group=groups[i]; const statusOpen=data.some(g=> g.ort === group &&
            g.status === 'open');
            groupHeaderList[i].style.backgroundColor = (statusOpen) ? '#E74C3C' : '#2ECC71';
        }
    });

      
    table.on("tableBuilt", function() {return console.log("from tableBuilt event")});
    
    (function(scope) { 
        scope.$watch('msg', function(msg) {
            if(msg) {
                var tabledata = msg.payload;
                table.replaceData(tabledata);
                
            }
        });
    })(scope);

</script>

I don't know how to make table.replaceData(tabledata); in scope.$watch wait for the tableBuild event though?

Can someone help me with this?

I have found a solution.
I just give the tableBuild some time. Like this:

(function(scope) { 
        scope.$watch('msg', function(msg) {
            if(msg) {
                setTimeout(function() {
                    var tabledata = msg.payload;
                    table.replaceData(tabledata);
                }, 200);
            }
        });
    })(scope);

However I am not a web/JS developer so I can't figure out a better solution.

It would certainly be better if I could query a status that is set by tableBuild.

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