# Header Filter UI Table for payload that keeps updating every second

**URL:** <https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747>\
**Category:** Dashboard\
**Created:** [9 October 2022 07:01 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747 "2022-10-09T07:01:13Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kimo](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@Kimo](https://discourse.nodered.org/u/Kimo)\
**Post date:** [9 October 2022 07:01 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/1 "2022-10-09T07:01:13Z")

</div>

Hi all,  
Currently I have a UI Table with headerFilter feature to filter out rows. Yes it is working for data that static. However, if I have to udpate my ui table every second to display a counting time (note: data is selected from SQL table), the header filter is no longer functioning bcs it keeps refreshing every second also.

Hve been looking to these threads and it was good reference for static data but not for above issue.

> [@Tabulator Filter](https://discourse.nodered.org/t/tabulator-filter/45646/3):
>
> Perhaps my last answer was a little bit short (posted on the go), sorry for that What I wanted to suggest. You can place a dropdonw widget as a field selector and type together with an input widget for the value and collect the outputs (perhaps in flow context). A button widget can then send a command to activate the filter function of tabulator: Example: The javascript code: table.setFilter("age", "\>", 10); translate to this message to be send to ui-table to activate the filter {"payload":{…

> [@How can i filter data table (ui\_table) by date?](https://discourse.nodered.org/t/how-can-i-filter-data-table-ui-table-by-date/28122/8):
>
> oh, filter by date... indeed I misread, laughing For filtering i just dd this property in each column: "headerFilter": "input"

This is my flow for reference. Any help would be appreciated. Thanks all!

```auto
[
    {
        "id": "c12357d81924ec43",
        "type": "tab",
        "label": "Flow 4",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "804e157652baac05",
        "type": "inject",
        "z": "c12357d81924ec43",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "1",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 330,
        "y": 360,
        "wires": [
            [
                "b932ddbc5407269b"
            ]
        ]
    },
    {
        "id": "b932ddbc5407269b",
        "type": "function",
        "z": "c12357d81924ec43",
        "name": "Select from DB",
        "func": "var array = flow.get ('array');\n\nif (array == undefined || array.length == 0)\n{\n msg.payload = \"\";\n return [msg,null];\n}\nelse\n{\n \nconst output1 = array.map(({ Name }) => Name);\nconst name = \"(\" + output1.map(e => \"'\" + e + \"'\").join(\",\") + \")\"\n\nconst output2 = array.map(({ ID }) => ID);\nconst id = \"(\" + output2.map(e => \"'\" + e + \"'\").join(\",\") + \")\"\n\n\nmsg.payload = \"SELECT [Name], [ID], [Country], [Job], [Weight], [Status],[Queueing Time] FROM [dbo].[Data] WHERE [Name] IN \"+name+\" AND [ID] IN \"+id+\" \" ;\nreturn [null,msg];\n}\n",
        "outputs": 2,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 540,
        "y": 360,
        "wires": [
            [
                "4582a0cbfb461040"
            ],
            [
                "73a23bb8b9168f4b"
            ]
        ]
    },
    {
        "id": "73a23bb8b9168f4b",
        "type": "MSSQL",
        "z": "c12357d81924ec43",
        "mssqlCN": "4f196903a82a4258",
        "name": "",
        "outField": "payload",
        "returnType": 0,
        "throwErrors": 1,
        "query": "",
        "modeOpt": "queryMode",
        "modeOptType": "query",
        "queryOpt": "payload",
        "queryOptType": "editor",
        "paramsOpt": "queryParams",
        "paramsOptType": "none",
        "rows": "rows",
        "rowsType": "msg",
        "params": [],
        "x": 740,
        "y": 400,
        "wires": [
            [
                "831b6ea232c8488c"
            ]
        ]
    },
    {
        "id": "831b6ea232c8488c",
        "type": "rbe",
        "z": "c12357d81924ec43",
        "name": "",
        "func": "rbe",
        "gap": "",
        "start": "",
        "inout": "out",
        "septopics": true,
        "property": "payload",
        "topi": "topic",
        "x": 910,
        "y": 400,
        "wires": [
            [
                "4582a0cbfb461040"
            ]
        ]
    },
    {
        "id": "4582a0cbfb461040",
        "type": "function",
        "z": "c12357d81924ec43",
        "name": "Push to Table",
        "func": "if (msg.payload == null || msg.payload == \"\")\n{\n var col = [];\n msg.ui_control = \n{\n \"tabulator\": {\n \"columns\": col\n }\n}\nreturn msg;\n}\n\nelse\n{\n var key = Object.keys(msg.payload[0]);\n flow.set ('object',key[0]);\n var arr = [];\n var col = [];\n\nfor(i = 0; i <key.length; i++){\n arr = {\n \"title\": key[i],\n \"field\": key[i],\n \"headerFilter\": \"input\"\n }\n col.push(arr)\n}\n\nmsg.ui_control = \n{\n \"tabulator\": {\n \"columns\": col\n }\n}\nreturn msg;\n}\n\n\n\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1080,
        "y": 360,
        "wires": [
            [
                "0ad3cc426f36483c"
            ]
        ]
    },
    {
        "id": "0ad3cc426f36483c",
        "type": "ui_table",
        "z": "c12357d81924ec43",
        "group": "bc09249168d821ac",
        "name": "Washer New",
        "order": 1,
        "width": 30,
        "height": 5,
        "columns": [],
        "outputs": 1,
        "cts": true,
        "x": 1290,
        "y": 360,
        "wires": [
            []
        ]
    },
    {
        "id": "4f196903a82a4258",
        "type": "MSSQL-CN",
        "tdsVersion": "7_4",
        "name": "Test",
        "server": "LALU\\SQL2019",
        "port": "1433",
        "encyption": true,
        "trustServerCertificate": true,
        "database": "Test",
        "useUTC": true,
        "connectTimeout": "15000",
        "requestTimeout": "15000",
        "cancelTimeout": "5000",
        "pool": "5",
        "parseJSON": false,
        "enableArithAbort": true
    },
    {
        "id": "bc09249168d821ac",
        "type": "ui_group",
        "name": "Patient",
        "tab": "7dcc246f.ee661c",
        "order": 3,
        "disp": false,
        "width": "30",
        "collapse": false,
        "className": ""
    },
    {
        "id": "7dcc246f.ee661c",
        "type": "ui_tab",
        "name": "TEST",
        "icon": "dashboard",
        "order": 3,
        "disabled": false,
        "hidden": false
    }
]

```

---

<div class="post-metadata">

**Author:** ![Kimo](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@Kimo](https://discourse.nodered.org/u/Kimo)\
**Post date:** [11 October 2022 06:42 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/2 "2022-10-11T06:42:25Z")

</div>

Is there anyone have thought on this?

---

<div class="post-metadata">

**Author:** ![E1cid](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/e1cid/32/77971_2.png) [@E1cid](https://discourse.nodered.org/u/E1cid)\
**Post date:** [11 October 2022 13:03 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/3 "2022-10-11T13:03:00Z")

</div>

The filter node can not compare objects unless you convert them to strings.  
You could convert the return names to a string and then compare if that string changes.  
e.g.

```auto
[{"id":"b932ddbc5407269b","type":"function","z":"c12357d81924ec43","name":"Select from DB","func":"var array = flow.get ('array');\n\nif (array == undefined || array.length == 0)\n{\n msg.payload = \"\";\n return [msg,null];\n}\nelse\n{\n \nconst output1 = array.map(({ Name }) => Name);\nconst name = \"(\" + output1.map(e => \"'\" + e + \"'\").join(\",\") + \")\"\n\nconst output2 = array.map(({ ID }) => ID);\nconst id = \"(\" + output2.map(e => \"'\" + e + \"'\").join(\",\") + \")\"\n\n\nmsg.payload = \"SELECT [Name], [ID], [Country], [Job], [Weight], [Status],[Queueing Time] FROM [dbo].[Data] WHERE [Name] IN \"+name+\" AND [ID] IN \"+id+\" \" ;\nreturn [null,msg];\n}\n","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":360,"wires":[["4582a0cbfb461040"],["73a23bb8b9168f4b"]]},{"id":"804e157652baac05","type":"inject","z":"c12357d81924ec43","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":330,"y":360,"wires":[["b932ddbc5407269b"]]},{"id":"4582a0cbfb461040","type":"function","z":"c12357d81924ec43","name":"Push to Table","func":"if (msg.payload == null || msg.payload == \"\")\n{\n var col = [];\n msg.ui_control = \n{\n \"tabulator\": {\n \"columns\": col\n }\n}\nreturn msg;\n}\n\nelse\n{\n var key = Object.keys(msg.payload[0]);\n flow.set ('object',key[0]);\n var arr = [];\n var col = [];\n\nfor(i = 0; i <key.length; i++){\n arr = {\n \"title\": key[i],\n \"field\": key[i],\n \"headerFilter\": \"input\"\n }\n col.push(arr)\n}\n\nmsg.ui_control = \n{\n \"tabulator\": {\n \"columns\": col\n }\n}\nreturn msg;\n}\n\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1080,"y":360,"wires":[["0ad3cc426f36483c"]]},{"id":"73a23bb8b9168f4b","type":"MSSQL","z":"c12357d81924ec43","mssqlCN":"4f196903a82a4258","name":"","outField":"payload","returnType":0,"throwErrors":1,"query":"","modeOpt":"queryMode","modeOptType":"query","queryOpt":"payload","queryOptType":"editor","paramsOpt":"queryParams","paramsOptType":"none","rows":"rows","rowsType":"msg","params":[],"x":740,"y":400,"wires":[["285c527b5e6d5803"]]},{"id":"831b6ea232c8488c","type":"rbe","z":"c12357d81924ec43","name":"","func":"rbe","gap":"","start":"","inout":"out","septopics":true,"property":"fiilter","topi":"topic","x":930,"y":460,"wires":[["4582a0cbfb461040"]]},{"id":"0ad3cc426f36483c","type":"ui_table","z":"c12357d81924ec43","group":"bc09249168d821ac","name":"Washer New","order":1,"width":30,"height":5,"columns":[],"outputs":1,"cts":true,"x":1290,"y":360,"wires":[[]]},{"id":"285c527b5e6d5803","type":"change","z":"c12357d81924ec43","name":"","rules":[{"t":"set","p":"filter","pt":"msg","to":"$string($$.payload.Name)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":770,"y":460,"wires":[["831b6ea232c8488c"]]},{"id":"bc09249168d821ac","type":"ui_group","name":"Patient","tab":"7dcc246f.ee661c","order":3,"disp":false,"width":"30","collapse":false,"className":""},{"id":"7dcc246f.ee661c","type":"ui_tab","name":"TEST","icon":"dashboard","order":3,"disabled":false,"hidden":false}]

```

But it may be better to do a sql query for updated info from table then just add the changes. There is a sub flow from @Christian-Me that is useful for uit-table [https://flows.nodered.org/flow/35d0480ce9151b2a722fa9d185a37825](https://flows.nodered.org/flow/35d0480ce9151b2a722fa9d185a37825)

[edit] or maybe slow down the update. 1 second is not really good as table could be constantly updateing every second, try maybe 15 seconds.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [11 October 2022 13:27 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/4 "2022-10-11T13:27:01Z")

</div>

> [@E1cid](#):
>
> The filter node can not compare objects

I don't think that is correct. The filter node will work with objects. I suspect it converts them to a json string if necessary.

---

<div class="post-metadata">

**Author:** ![E1cid](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/e1cid/32/77971_2.png) [@E1cid](https://discourse.nodered.org/u/E1cid)\
**Post date:** [11 October 2022 13:41 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/5 "2022-10-11T13:41:04Z")

</div>

Yes indeed, simple object. Maybe you have some idea what the issue is then?

---

<div class="post-metadata">

**Author:** ![madhouse](https://avatars.discourse-cdn.com/v4/letter/m/b77776/32.png) [@madhouse](https://discourse.nodered.org/u/madhouse)\
**Post date:** [11 October 2022 16:02 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/6 "2022-10-11T16:02:12Z")

</div>

You're not going to want to hear this, but you're going to want to ditch the table nodes and use a ui-template node to actually build Tabulator tables. Dashboard-ui-table was built on the Tabulator system that existed a couple years ago. It's been heavily modified since then. Also, the way ui-table was built, any time you redo the data, it completely resets and redraws the table. Not good if you're trying to do work while dynamically updating data in the table.

Using ui-template to build an actual Tabulator table seems daunting, but it's really easy. You just need two template nodes to do it. The first template node inserts the Tabulator source in the header of your dashboard page. Simply set your template to Add to site head section and insert the following code:

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

```

The second node is slightly trickier, but still very simple. It will consist of this:

```auto
<script>
    (some code)
    ...
</script>

```

Inside that script section is where you'll build your tabulator table. Navigate to [tabulator.info](http://tabulator.info) and you'll find oodles of documentation and examples you can literally copy/paste from and have your table instantly work. All you need to do is know where your data is coming from and how to get it into your table.

Now to the reason why I said all that (after several weeks of beating my head against the wall with ui-table and finally ditching it for this method). Using Tabulator itself lends to two things. First, it's all recent code that is updated and works. Second, when you have dynamic data that keeps refreshing, raw Tabulator tables will just change the data where it sits and leave things like filters and whatnot alone. That's something ui-table just isn't built to do. So you can update data every second and have a running filter that keeps filtering it every time it's updated.

It's going to take some getting used to, but with the examples and documentation, you can do it.

---

<div class="post-metadata">

**Author:** ![madhouse](https://avatars.discourse-cdn.com/v4/letter/m/b77776/32.png) [@madhouse](https://discourse.nodered.org/u/madhouse)\
**Post date:** [11 October 2022 17:27 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/7 "2022-10-11T17:27:34Z")

</div>

Clicking the correct reply to ensure this gets flagged.

---

<div class="post-metadata">

**Author:** ![Kimo](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@Kimo](https://discourse.nodered.org/u/Kimo)\
**Post date:** [12 October 2022 01:20 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/8 "2022-10-12T01:20:02Z")

</div>

Thank you madhouse. This really helpful to direct me. Actually I was using ui template to build my table previously and changed to ui table due to simplicity.

---

<div class="post-metadata">

**Author:** ![Kimo](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@Kimo](https://discourse.nodered.org/u/Kimo)\
**Post date:** [12 October 2022 03:13 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/9 "2022-10-12T03:13:22Z")

</div>

If I use below code for the table, where should I put the headerFilter class/function to enable the filter on each column? or need a function bfore the template node?

```auto
<style>
    #history {
      font-family: "Arial";
        border-collapse: collapse;
        width: 100%;
        }
        
        #history td, #history th {
        border: 1px solid #ddd;
        padding: 8px;
        }
        #history tr:nth-child(even){background-color: #A8EEF8;}
        
        #history tr:hover {background-color: #40aeea;}
        
        #history th {
        padding-top: 12px;
        padding-bottom: 12px;
        text-align: center;
        background-color: #696969;
        color: white;
        }
        </style>
        
        <table id="history" border="1">
            <tr align="center">

                 <th>Name</th>
                 <th>ID</th>
                 <th>Country</th>
               
            </tr>
                <tbody>
                    <tr align="center" ng-repeat="row in msg.payload">
                        <td ng-repeat="item in row" >{{item}}</td>
                        </tr>
                        </tbody>
                        </table>
        

```

I want the filter something like this

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/a/6/a6c649f7ff6f8f8df506ef819426e50290b9728d.png)

---

<div class="post-metadata">

**Author:** ![Kimo](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@Kimo](https://discourse.nodered.org/u/Kimo)\
**Post date:** [12 October 2022 03:34 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/10 "2022-10-12T03:34:10Z")

</div>

And I dont think so that inside a template node, you can add copy/paste from tabulator.info bcs what I know tabulator.info is meant for ui-table node, not html table. Correct me if I'm wrong

---

<div class="post-metadata">

**Author:** ![madhouse](https://avatars.discourse-cdn.com/v4/letter/m/b77776/32.png) [@madhouse](https://discourse.nodered.org/u/madhouse)\
**Post date:** [12 October 2022 05:42 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/11 "2022-10-12T05:42:31Z")

</div>

So, here is what you say you want.

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/6/6/66634026a3ba3d6409b3d32fd0c0f12fb342bad5.png)  
Here is the source code for it from the web page.  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/8/d80139a988ab75f6a0f5f1af504efac6e516f953.png)

```auto
//custom max min header filter
var minMaxFilterEditor = function(cell, onRendered, success, cancel, editorParams){

    var end;

    var container = document.createElement("span");

    //create and style inputs
    var start = document.createElement("input");
    start.setAttribute("type", "number");
    start.setAttribute("placeholder", "Min");
    start.setAttribute("min", 0);
    start.setAttribute("max", 100);
    start.style.padding = "4px";
    start.style.width = "50%";
    start.style.boxSizing = "border-box";

    start.value = cell.getValue();

    function buildValues(){
        success({
            start:start.value,
            end:end.value,
        });
    }

    function keypress(e){
        if(e.keyCode == 13){
            buildValues();
        }

        if(e.keyCode == 27){
            cancel();
        }
    }

    end = start.cloneNode();
    end.setAttribute("placeholder", "Max");

    start.addEventListener("change", buildValues);
    start.addEventListener("blur", buildValues);
    start.addEventListener("keydown", keypress);

    end.addEventListener("change", buildValues);
    end.addEventListener("blur", buildValues);
    end.addEventListener("keydown", keypress);

    container.appendChild(start);
    container.appendChild(end);

    return container;
 }

//custom max min filter function
function minMaxFilterFunction(headerValue, rowValue, rowData, filterParams){
    //headerValue - the value of the header filter element
    //rowValue - the value of the column in this row
    //rowData - the data for the row being filtered
    //filterParams - params object passed to the headerFilterFuncParams property

        if(rowValue){
            if(headerValue.start != ""){
                if(headerValue.end != ""){
                    return rowValue >= headerValue.start && rowValue <= headerValue.end;
                }else{
                    return rowValue >= headerValue.start;
                }
            }else{
                if(headerValue.end != ""){
                    return rowValue <= headerValue.end;
                }
            }
        }

    return true; //must return a boolean, true if it passes the filter.
}

var table = new Tabulator("#example-table", {
    height:"311px",
    layout:"fitColumns",
    columns:[
        {title:"Name", field:"name", width:150, headerFilter:"input"},
        {title:"Progress", field:"progress", width:150, formatter:"progress", sorter:"number", headerFilter:minMaxFilterEditor, headerFilterFunc:minMaxFilterFunction, headerFilterLiveFilter:false},
        {title:"Gender", field:"gender", editor:"list", editorParams:{values:{"male":"Male", "female":"Female", clearable:true}}, headerFilter:true, headerFilterParams:{values:{"male":"Male", "female":"Female", "":""}, clearable:true}},
        {title:"Rating", field:"rating", editor:"star", hozAlign:"center", width:100, headerFilter:"number", headerFilterPlaceholder:"at least...", headerFilterFunc:">="},
        {title:"Favourite Color", field:"col", editor:"input", headerFilter:"list", headerFilterParams:{valuesLookup:true, clearable:true}},
        {title:"Date Of Birth", field:"dob", hozAlign:"center", sorter:"date", headerFilter:"input"},
        {title:"Driver", field:"car", hozAlign:"center", formatter:"tickCross", headerFilter:"tickCross", headerFilterParams:{"tristate":true},headerFilterEmptyCheck:function(value){return value === null}},
    ],
});

```

Here is the resulting flow that I built with just copy/paste from the web page.

```auto
[{"id":"250290d53b07a92d","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"13c9bb7afaec28ee","type":"ui_template","z":"250290d53b07a92d","group":"e20c5b3c6a494e25","name":"","order":1,"width":0,"height":0,"format":"<link href=\"https://unpkg.com/tabulator-tables/dist/css/tabulator_site.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","className":"","x":80,"y":40,"wires":[[]]},{"id":"5b1eaa2da8011171","type":"ui_template","z":"250290d53b07a92d","group":"e20c5b3c6a494e25","name":"","order":2,"width":0,"height":0,"format":"<div id=\"example-table\"></div>\n<script>\n //sample data to be used in all tabulators\n var tabledata = [\n {id:1, name:\"Oli Bob\", progress:12, location:\"United Kingdom\", gender:\"male\", rating:1, col:\"red\", dob:\"14/04/1984\",\n car:1, lucky_no:5, lorem:\"Lorem ipsum dolor sit amet, elit consectetur adipisicing \"},\n {id:2, name:\"Mary May\", progress:1, location:\"Germany\", gender:\"female\", rating:2, col:\"blue\", dob:\"14/05/1982\",\n car:true, lucky_no:10, lorem:\"Lorem ipsum dolor sit amet, elit consectetur adipisicing \"},\n {id:3, name:\"Christine Lobowski\", progress:42, location:\"France\", gender:\"female\", rating:0, col:\"green\",\n dob:\"22/05/1982\", car:\"true\", lucky_no:12, lorem:\"Lorem ipsum dolor sit amet, elit consectetur adipisicing \"},\n {id:4, name:\"Brendon Philips\", progress:100, location:\"USA\", gender:\"male\", rating:1, col:\"orange\", dob:\"01/08/1980\",\n car:false, lucky_no:18, lorem:\"Lorem ipsum dolor sit amet, elit consectetur adipisicing \"},\n {id:5, name:\"Margret Marmajuke\", progress:16, location:\"Canada\", gender:\"female\", rating:5, col:\"yellow\",\n dob:\"31/01/1999\", car:false, lucky_no:33, lorem:\"Lorem ipsum dolor sit amet, elit consectetur adipisicing \"},\n {id:6, name:\"Frank Harbours\", progress:38, location:\"Russia\", gender:\"male\", rating:4, col:\"red\", dob:\"12/05/1966\",\n car:1, lucky_no:2, lorem:\"Lorem ipsum dolor sit amet, elit consectetur adipisicing \"},\n {id:7, name:\"Jamie Newhart\", progress:23, location:\"India\", gender:\"male\", rating:3, col:\"green\", dob:\"14/05/1985\",\n car:true, lucky_no:63, lorem:\"Lorem ipsum dolor sit amet, elit consectetur adipisicing \"},\n {id:8, name:\"Gemma Jane\", progress:60, location:\"China\", gender:\"female\", rating:0, col:\"red\", dob:\"22/05/1982\",\n car:\"true\", lucky_no:72, lorem:\"Lorem ipsum dolor sit amet, elit consectetur adipisicing \"},\n {id:9, name:\"Emily Sykes\", progress:42, location:\"South Korea\", gender:\"female\", rating:1, col:\"maroon\",\n dob:\"11/11/1970\", car:false, lucky_no:44, lorem:\"Lorem ipsum dolor sit amet, elit consectetur adipisicing \"},\n {id:10, name:\"James Newman\", progress:73, location:\"Japan\", gender:\"male\", rating:5, col:\"red\", dob:\"22/03/1998\",\n car:false, lucky_no:9, lorem:\"Lorem ipsum dolor sit amet, elit consectetur adipisicing \"},\n];\n \n var tabledatasimple = [\n {id:1, name:\"Oli Bob\", location:\"United Kingdom\", gender:\"male\", rating:1, col:\"red\", dob:\"14/04/1984\"},\n {id:2, name:\"Mary May\", location:\"Germany\", gender:\"female\", rating:2, col:\"blue\", dob:\"14/05/1982\"},\n {id:3, name:\"Christine Lobowski\", location:\"France\", gender:\"female\", rating:0, col:\"green\", dob:\"22/05/1982\"},\n {id:4, name:\"Brendon Philips\", location:\"USA\", gender:\"male\", rating:1, col:\"orange\", dob:\"01/08/1980\"},\n {id:5, name:\"Margret Marmajuke\", location:\"Canada\", gender:\"female\", rating:5, col:\"yellow\", dob:\"31/01/1999\"},\n {id:6, name:\"Frank Harbours\", location:\"Russia\", gender:\"male\", rating:4, col:\"red\", dob:\"12/05/1966\"},\n {id:7, name:\"Jamie Newhart\", location:\"India\", gender:\"male\", rating:3, col:\"green\", dob:\"14/05/1985\"},\n {id:8, name:\"Gemma Jane\", location:\"China\", gender:\"female\", rating:0, col:\"red\", dob:\"22/05/1982\"},\n {id:9, name:\"Emily Sykes\", location:\"South Korea\", gender:\"female\", rating:1, col:\"maroon\", dob:\"11/11/1970\"},\n {id:10, name:\"James Newman\", location:\"Japan\", gender:\"male\", rating:5, col:\"red\", dob:\"22/03/1998\"},\n];\n \n var tableDataNested = [\n {id:1, name:\"Oli Bob\", location:\"United Kingdom\", gender:\"male\", rating:1, col:\"red\", dob:\"14/04/1984\", car:1,\n lucky_no:5, _children:[\n {id:2, name:\"Mary May\", progress:1, location:\"Germany\", gender:\"female\", rating:2, col:\"blue\", dob:\"14/05/1982\",\n car:true, lucky_no:10},\n {id:3, name:\"Christine Lobowski\", progress:42, location:\"France\", gender:\"female\", rating:0, col:\"green\",\n dob:\"22/05/1982\", car:\"true\", lucky_no:12},\n {id:4, name:\"Brendon Philips\", progress:100, location:\"USA\", gender:\"male\", rating:1, col:\"orange\", dob:\"01/08/1980\",\n lucky_no:18, _children:[\n {id:5, name:\"Margret Marmajuke\", progress:16, location:\"Canada\", gender:\"female\", rating:5, col:\"yellow\",\n dob:\"31/01/1999\", lucky_no:33},\n {id:6, name:\"Frank Harbours\", progress:38, location:\"Russia\", gender:\"male\", rating:4, col:\"red\", dob:\"12/05/1966\",\n car:1, lucky_no:2},\n]},\n ]},\n {id:7, name:\"Jamie Newhart\", progress:23, location:\"India\", gender:\"male\", rating:3, col:\"green\", dob:\"14/05/1985\",\n car:true, lucky_no:63},\n {id:8, name:\"Gemma Jane\", progress:60, location:\"China\", gender:\"female\", rating:0, col:\"red\", dob:\"22/05/1982\",\n car:\"true\", lucky_no:72, _children:[\n {id:9, name:\"Emily Sykes\", progress:42, location:\"South Korea\", gender:\"female\", rating:1, col:\"maroon\",\n dob:\"11/11/1970\", lucky_no:44},\n]},\n {id:10, name:\"James Newman\", progress:73, location:\"Japan\", gender:\"male\", rating:5, col:\"red\", dob:\"22/03/1998\",\n lucky_no:9},\n ];\n \n var tabledatabig = [\n {id:1, name:\"Oli Bob\", progress:12, gender:\"male\", rating:1, col:\"red\", dob:\"14/04/1984\", car:1, lucky_no:5},\n {id:2, name:\"Mary May\", progress:1, gender:\"female\", rating:2, col:\"blue\", dob:\"14/05/1982\", car:true, lucky_no:10},\n {id:3, name:\"Christine Lobowski\", progress:42, gender:\"female\", rating:0, col:\"green\", dob:\"22/05/1982\", car:\"true\",\n lucky_no:12},\n {id:4, name:\"Brendon Philips\", progress:100, gender:\"male\", rating:1, col:\"orange\", dob:\"01/08/1980\", lucky_no:18},\n {id:5, name:\"Margret Marmajuke\", progress:16, gender:\"female\", rating:5, col:\"yellow\", dob:\"31/01/1999\", lucky_no:33},\n {id:6, name:\"Frank Harbours\", progress:38, gender:\"male\", rating:4, col:\"red\", dob:\"12/05/1966\", car:1, lucky_no:2},\n {id:7, name:\"Jamie Newhart\", progress:23, gender:\"male\", rating:3, col:\"green\", dob:\"14/05/1985\", car:true,\n lucky_no:63},\n {id:8, name:\"Gemma Jane\", progress:60, gender:\"female\", rating:0, col:\"red\", dob:\"22/05/1982\", car:\"true\", lucky_no:72},\n {id:9, name:\"Emily Sykes\", progress:42, gender:\"female\", rating:1, col:\"maroon\", dob:\"11/11/1970\", lucky_no:44},\n {id:10, name:\"James Newman\", progress:73, gender:\"male\", rating:5, col:\"red\", dob:\"22/03/1998\", lucky_no:9},\n {id:11, name:\"Martin Barryman\", progress:20, gender:\"male\", rating:5, col:\"violet\", dob:\"04/04/2001\"},\n {id:12, name:\"Jenny Green\", progress:56, gender:\"female\", rating:4, col:\"indigo\", dob:\"12/11/1998\", car:true},\n {id:13, name:\"Alan Francis\", progress:90, gender:\"male\", rating:3, col:\"blue\", dob:\"07/08/1972\", car:true},\n {id:14, name:\"John Phillips\", progress:80, gender:\"male\", rating:1, col:\"green\", dob:\"24/09/1950\", car:true},\n {id:15, name:\"Ed White\", progress:70, gender:\"male\", rating:0, col:\"yellow\", dob:\"19/06/1976\"},\n {id:16, name:\"Paul Branderson\", progress:60, gender:\"male\", rating:5, col:\"orange\", dob:\"01/01/1982\"},\n {id:17, name:\"Gemma Jane\", progress:50, gender:\"female\", rating:2, col:\"red\", dob:\"14/04/1983\", car:true},\n {id:18, name:\"Emma Netwon\", progress:40, gender:\"female\", rating:4, col:\"brown\", dob:\"07/10/1963\", car:true},\n {id:19, name:\"Hannah Farnsworth\", progress:30, gender:\"female\", rating:1, col:\"pink\", dob:\"11/02/1991\"},\n {id:20, name:\"Victoria Bath\", progress:20, gender:\"female\", rating:2, col:\"purple\", dob:\"22/03/1986\"},\n];\n\n //custom max min header filter\nvar minMaxFilterEditor = function(cell, onRendered, success, cancel, editorParams){\n \n var end;\n \n var container = document.createElement(\"span\");\n \n //create and style inputs\n var start = document.createElement(\"input\");\n start.setAttribute(\"type\", \"number\");\n start.setAttribute(\"placeholder\", \"Min\");\n start.setAttribute(\"min\", 0);\n start.setAttribute(\"max\", 100);\n start.style.padding = \"4px\";\n start.style.width = \"50%\";\n start.style.boxSizing = \"border-box\";\n \n start.value = cell.getValue();\n \n function buildValues(){\n success({\n start:start.value,\n end:end.value,\n });\n };\n\n function keypress(e){\n if(e.keyCode == 13){\n buildValues();\n }\n \n if(e.keyCode == 27){\n cancel();\n }\n };\n \n end = start.cloneNode();\n end.setAttribute(\"placeholder\", \"Max\");\n \n start.addEventListener(\"change\", buildValues);\n start.addEventListener(\"blur\", buildValues);\n start.addEventListener(\"keydown\", keypress);\n \n end.addEventListener(\"change\", buildValues);\n end.addEventListener(\"blur\", buildValues);\n end.addEventListener(\"keydown\", keypress);\n \n \n container.appendChild(start);\n container.appendChild(end);\n \n return container;\n}\n \n //custom max min filter function\nfunction minMaxFilterFunction(headerValue, rowValue, rowData, filterParams){\n //headerValue - the value of the header filter element\n //rowValue - the value of the column in this row\n //rowData - the data for the row being filtered\n //filterParams - params object passed to the headerFilterFuncParams property\n \nif(rowValue){\n if(headerValue.start != \"\"){\n if(headerValue.end != \"\"){\n return rowValue >= headerValue.start && rowValue <= headerValue.end; }else{ return rowValue>= headerValue.start;\n }\n }\n else{\n if(headerValue.end != \"\"){\n return rowValue <= headerValue.end;}\n }\n }\n return true; //must return a boolean, true if it passes the filter. \n} \nvar table=new Tabulator(\"#example-table\", {\n height:\"311px\",\n layout:\"fitColumns\",\n data:tabledatabig,\n columns:[\n {title:\"Name\", field:\"name\", width:150, headerFilter:\"input\"},\n {title:\"Progress\", field:\"progress\", width:150, formatter:\"progress\", sorter:\"number\", headerFilter:minMaxFilterEditor, headerFilterFunc:minMaxFilterFunction, headerFilterLiveFilter:false},\n {title:\"Gender\", field:\"gender\", editor:\"list\", editorParams:{values:{\"male\":\"Male\", \"female\":\"Female\", clearable:true}}, headerFilter:true, headerFilterParams:{values:{\"male\":\"Male\", \"female\" :\"Female\", \"\" :\"\"}, clearable:true}},\n {title:\"Rating\", field:\"rating\", editor:\"star\", hozAlign:\"center\", width:100, headerFilter:\"number\", headerFilterPlaceholder:\"at least...\", headerFilterFunc:\">=\"},\n {title:\"Favourite Color\", field:\"col\", editor:\"input\", headerFilter:\"list\", headerFilterParams:{valuesLookup:true, clearable:true}},\n {title:\"Date Of Birth\", field:\"dob\", hozAlign:\"center\", sorter:\"date\", headerFilter:\"input\"},\n {title:\"Driver\", field:\"car\", hozAlign:\"center\", formatter:\"tickCross\", headerFilter:\"tickCross\", headerFilterParams:{\"tristate\":true},headerFilterEmptyCheck:function(value){return value === null}},\n],\n});\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":80,"y":80,"wires":[[]]},{"id":"e20c5b3c6a494e25","type":"ui_group","name":"Test","tab":"311b79f0d87bc5d7","order":9,"disp":true,"width":"30","collapse":false,"className":""},{"id":"311b79f0d87bc5d7","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

```

Looks like this:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/5/1/51a005a132e62759654ac483fed1cfd8ae8a6980.png)  
And produces this.

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/1/4/1476b7a25936734656062e7f63d45388aeead8a8.png)  
You can literally copy and paste the data from the Tabulator examples directly into the ui-template node and have it work. I changed only three things to make this table happen.

1. Not really a necessary change, but I changed the header section from tabulator.min.css to tabulator\_site.min.css to mimic the theme of the Tabulator site. Instructions on themes are on the site as well.
2. While not visible in the source code for the table, the table data was pulled from the developers console while on the Tabulator page and pasted into the second ut-template. Hitting F12 pulls up the developers console and browsing through the elements will land you the variables used for the table data.
3. The source code does not specify what data to use. I entered data:bigtabledata as one of the table setup options seen near the bottom of the source code in my flow.

The longest time I spent putting this together was trying to find a brace } that was hidden in a comment block due to how Node-Red pasted the code and not because of the code itself. The rest took less than five minutes total. Ui-table (library wrapper) was built to use Tabulator (source library) in Node-Red (IDE), not the other way around. Using Tabulator itself instead of the wrapper opens you up to the full functionality of Tabulator that the wrapper (ui-table) doesn't allow. And no, it's all Javascript based and not HTML based, though the Tabulator functionality is Javascript run inside HTML.

Hopefully that helps.

---

<div class="post-metadata">

**Author:** ![Kimo](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@Kimo](https://discourse.nodered.org/u/Kimo)\
**Post date:** [12 October 2022 07:12 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/12 "2022-10-12T07:12:17Z")

</div>

Thanks a lot. Really helpful. For the field part, if that have spaces between words, let say the field is Full Name (taken from SQL), the table wont show up. I tried to put

```auto
 field:"[Full Name]"

```

or

```auto
 field:["Full Name"]

```

or

```auto
 field:"[Full Name]"

```

Also not working

---

<div class="post-metadata">

**Author:** ![Kimo](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@Kimo](https://discourse.nodered.org/u/Kimo)\
**Post date:** [12 October 2022 07:35 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/13 "2022-10-12T07:35:03Z")

</div>

I know it's not recommended to have space on field name or SQL columns, but in case I have to face this situation.

---

<div class="post-metadata">

**Author:** ![Kimo](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@Kimo](https://discourse.nodered.org/u/Kimo)\
**Post date:** [12 October 2022 08:37 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/14 "2022-10-12T08:37:53Z")

</div>

I just tried to change the field name so it doesnt have spaces, but the outcome is the same (table not shown up). then, I want to check and tried to put inject node and function node that contains the object array of tabledatabig and change the data with msg.payload. The table also not showing up. It just works when data is inside the ui -template node. Maybe there's something wrong on how to push payload to the ui template node

```auto
var table=new Tabulator("#example-table", {
    height:"311px",
    layout:"fitColumns",
    data:msg.payload,
    columns:[
        {title:"Name", field:"name", width:150, headerFilter:"input"},
        {title:"Progress", field:"progress", width:150, formatter:"progress", sorter:"number", headerFilter:minMaxFilterEditor, headerFilterFunc:minMaxFilterFunction, headerFilterLiveFilter:false},
        {title:"Gender", field:"gender", editor:"list", editorParams:{values:{"male":"Male", "female":"Female", clearable:true}}, headerFilter:true, headerFilterParams:{values:{"male":"Male", "female" :"Female", "" :""}, clearable:true}},
        {title:"Rating", field:"rating", editor:"star", hozAlign:"center", width:100, headerFilter:"number", headerFilterPlaceholder:"at least...", headerFilterFunc:">="},
        {title:"Favourite Color", field:"col", editor:"input", headerFilter:"list", headerFilterParams:{valuesLookup:true, clearable:true}},
        {title:"Date Of Birth", field:"dob", hozAlign:"center", sorter:"date", headerFilter:"input"},
        {title:"Driver", field:"car", hozAlign:"center", formatter:"tickCross", headerFilter:"tickCross", headerFilterParams:{"tristate":true},headerFilterEmptyCheck:function(value){return value === null}},
    ],
});
</script>

```

---

<div class="post-metadata">

**Author:** ![Kimo](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@Kimo](https://discourse.nodered.org/u/Kimo)\
**Post date:** [12 October 2022 08:50 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/15 "2022-10-12T08:50:45Z")

</div>

Also on your flow, if you refresh the page, the table will disappear

---

<div class="post-metadata">

**Author:** ![madhouse](https://avatars.discourse-cdn.com/v4/letter/m/b77776/32.png) [@madhouse](https://discourse.nodered.org/u/madhouse)\
**Post date:** [12 October 2022 14:44 UTC](https://discourse.nodered.org/t/header-filter-ui-table-for-payload-that-keeps-updating-every-second/68747/16 "2022-10-12T14:44:46Z")

</div>

> [@Kimo](#):
>
> Thanks a lot. Really helpful. For the field part, if that have spaces between words, let say the field is Full Name (taken from SQL), the table wont show up. I tried to put
> 
> ```auto
> field:"[Full Name]"
> 
> ```

> [@Kimo](#):
>
> I know it's not recommended to have space on field name or SQL columns, but in case I have to face this situation.

This is a very simple fix. Don't use brackets. They're not supposed to get used. This is the actual name of the key you're looking for in the payload and spaces don't matter because Javascript uses JSON which essentially treats it as a string.

```auto
field:"Full Name"

```

> [@Kimo](#):
>
> I just tried to change the field name so it doesnt have spaces, but the outcome is the same (table not shown up). then, I want to check and tried to put inject node and function node that contains the object array of tabledatabig and change the data with msg.payload. The table also not showing up. It just works when data is inside the ui -template node. Maybe there's something wrong on how to push payload to the ui template node

> [@Kimo](#):
>
> ```auto
> var table=new Tabulator("#example-table", {
> height:"311px",
> layout:"fitColumns",
> data:msg.payload,
> 
> ```

Yes. This will require some reading beyond what is written in Tabulator because this is something you have to find more specifically for Node-Red. Implementing Tabulator in this way causes it to be _asynchronous_ with the rest of the code. It loads according to the user on the web page, not according to the server. The code runs in the browser and reaches for the server whenever it needs to. When the table loads in the browser for the user, msg.payload most likely won't exist so no data. This needs an asynchronous way of handling it.

```auto
(function(scope) {

    scope.test = function(msg) {
        table.setData(msg.payload);
    }

})(scope)

```

Right now, I don't have access to how my tabulator deals with it, but you will put a block of code very similar to the above in your code somewhere. I will post the corrected code when I can get to it. But essentially, the code monitors for some kind of input to the ui-template node (which means the input will have to be tied to something that sends messages in Node-Red) and performs some kind of response when one arrives. That also means you completely remove your data:msg.payload line from your table setup. Your table will form with the column definitions and wait for data to be loaded in for it to display. Once it has data, it will display it.

This also brings up another point. You're pulling your data from an SQL database. You really shouldn't push the data to the table, but instead allow the table to pull the data by using an AJAX setup in the table and adding a HTTP in node in your flow connected to a function that pushes your query to your database and returns the result to the HTTP out node. Then the table can call it whenever it wants and load dynamically. I will leave you to research that on your own. It is very easy to use HTTP nodes and the AJAX setup is well documented on the website. It would be nice if Tabulator had a method of making an SQL query, but that has not been implemented. Likely because of everything that must go into it.

> [@Kimo](#):
>
> Also on your flow, if you refresh the page, the table will disappear

Yes. This is a part of how Javascript, HTML, your browser and Node-Red work. This is well beyond the scope of your question and would require a lot of in depth research to make it work properly. Short answer is the Dashboard created for Node-Red doesn't handle reloading Javascript sources nicely. There are some workarounds to get it to reload, but they're not very effective. If your Dashboard UI has multiple tabs, you can switch to a different tab and back which usually forces a reload and will display your table. Ui-control nodes also put out information on when a page is accessed or disconnected, which can be used to control some stuff. But the short answer is reload shouldn't be used and should be replaced in page handling with switching tabs or proper coding.

You will need to do a lot of reading in Tabulator to learn how to adjust your table code to fit what you're trying to load. The code I used to show the header filtering came straight from the examples and is setup to work with the example data. You're going to need to define your own columns from your own data, setup your own sources and add in the functionality you need for what you want it to do. That would take up several threads in this forum if the discussion kept going as it is. You've been seeded with everything you'll need to get started (once I correct my code for the msg.payload injection), so you should be good to go after some reading. Give it a try and if you get stuck on something that doesn't seem to be working, jump back on and we'll be glad to help. The nice thing is this stuff is pretty easy to manipulate and Javascript in general is well documented. I think you'll do just fine.
