# Problem with tabulator.js in ui-template

**URL:** https://discourse.nodered.org/t/problem-with-tabulator-js-in-ui-template/68782
**Category:** Dashboard
**Created:** [9 October 2022 22:08 UTC](https://discourse.nodered.org/t/problem-with-tabulator-js-in-ui-template/68782 "2022-10-09T22:08:20Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![rewegit](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rewegit/32/4778_2.png) [@rewegit](https://discourse.nodered.org/u/rewegit)
#### Post date: [9 October 2022 22:08 UTC](https://discourse.nodered.org/t/problem-with-tabulator-js-in-ui-template/68782/1 "2022-10-09T22:08:20Z")

</div>

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

```auto
[
    {
        "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:

```auto
<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?

---

<div class="post-metadata">

### Author: ![rewegit](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rewegit/32/4778_2.png) [@rewegit](https://discourse.nodered.org/u/rewegit)
#### Post date: [10 October 2022 22:39 UTC](https://discourse.nodered.org/t/problem-with-tabulator-js-in-ui-template/68782/2 "2022-10-10T22:39:35Z")

</div>

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

```auto
(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.

---

<div class="post-metadata">

### Author: ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)
#### Post date: [9 November 2022 22:39 UTC](https://discourse.nodered.org/t/problem-with-tabulator-js-in-ui-template/68782/3 "2022-11-09T22:39:37Z")

</div>

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