# Using Tabulator grids in Dashboard v2.0 templates

**URL:** <https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068>\
**Category:** Dashboard\
**Tags:** dashboard-2\
**Created:** [31 January 2024 11:43 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068 "2024-01-31T11:43:06Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [7 March 2024 15:59 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/21 "2024-03-07T15:59:54Z")

</div>

Thanks @joepavitt , this is very helpful

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [10 March 2024 15:25 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/22 "2024-03-10T15:25:36Z")

</div>

Hi @joepavitt,  
The custom node is progressing nicely, and I am succeeding to load & interact with the table.  
2 quick questions:

1. What is the best way to import the Tabulator's CSS file. I currently import it as an `href` from a URL, but want the node to be self -contained and not rely on external locations. `@import` doesn't work - it is rejected by the build process

2. I notice that the `onInput()` handler receives a `done()` function.  
In regular custom nodes, `done()` should be called after the node finishes processing the incoming message (including all async callbacks).  
Should I call `done()` once `onInput()` completes? what if the client-side node is still running? For example, many of the Tabulator methods are async, and I send their response only after they complete processing. Should I also issue a `done()` after that? and if yes, how do I get this function in the `this.$socket.on()` listener?

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [12 March 2024 10:00 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/23 "2024-03-12T10:00:32Z")

</div>

> [@omrid](#):
>
> What is the best way to import the Tabulator's CSS file. I currently import it as an `href` from a URL, but want the node to be self -contained and not rely on external locations. `@import` doesn't work - it is rejected by the build process

I would expect that you can put the `css` file into a `/ui/stylesheets` folder, then in your component's `.vue` file in the `<style></sctyle>` you should be able to `@import ""`.

Noticed you've tried this though, so I'll need to investigate further. I've opened [Third Party: Cannot @import in CSS · Issue #663 · FlowFuse/node-red-dashboard · GitHub](https://github.com/FlowFuse/node-red-dashboard/issues/663) to track

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [12 March 2024 16:42 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/24 "2024-03-12T16:42:50Z")

</div>

Tried to reproduce locally, and it's working for me. Have opened a [PR](https://github.com/FlowFuse/node-red-dashboard-2-ui-example/pull/9) (hopefully merging soon) which demonstrates in the base `ui-example` how to do it.

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [13 March 2024 10:34 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/25 "2024-03-13T10:34:29Z")

</div>

Solved!  
@import did not work when inside the default `<style scoped>` section.  
when I put it in a separate `<style>...</style>` section, it imports successfully.  
Thanks @joepavitt

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [14 March 2024 17:14 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/26 "2024-03-14T17:14:26Z")

</div>

Hi @joepavitt, another quick question:  
Each Tabulator instance maps to a unique `div id` in the ui page, for example:

```auto
<template>
<div id="abcdef"></div>
</template>

<script>
...
this.table = new Tabulator('#abcdef',InitObj);
...
</script>

```

In order to support multiple table nodes on the same page, I need to ensure `div id` uniqueness. The solution I found is to use a generic `div id` and dynamically update it with a unique value, as follows:

```auto
<template>
<div id="tableContainer"></div>
</template>
<script>
...
mounted () {
   this.tblId = this.props.tblId || 'tbl'+Math.random().toString(12).substr(2, 12);
   let tblDiv = document.getElementById('tblContainer');
   tblDiv.id = this.tblId;
...
</script>

```

This works well. Yet I understand that behind the scenes the `<template>` sections of the various table nodes are combined into a single HTML page, resulting in multiple `div`s, with the same id ('TblContainer'), which then get unique Ids upon table node mounting.

I know that `document.getElementById()` returns the first element it finds (hence, after changing its id, next time it will retrieve the following one etc.).  
To ensure the table nodes do not get mixed up - am I safe to assume that these `div`s are retrieved from the DOM in the same order they were defined in the page, i.e. the node order in the group hierarchy?

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [14 March 2024 17:40 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/27 "2024-03-14T17:40:46Z")

</div>

No need, Vue comes built in with a cleaner alternative call `ref`.

You can assign `ref="myDiv"` in your HTML, then in your JS, you can `this.$refs.myDiv` and it just works, tou can copy and paste it as much as you like, and `this.$refs` will always stay constrained to that instance of the `ui-template`

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [14 March 2024 19:22 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/28 "2024-03-14T19:22:36Z")

</div>

Thanks @joepavitt, I will try it.  
Does this still give me the ability to set a specified div id for each table instance?

The reason I am asking, is that in addition to the "classic" Node-red way of configuring, writing & reading the table via flow messages, I want to also enable direct API access (where makes sense), which can simplify the flows.

For example, allowing a supporting template node with button & drop-down controls to set the table appearance, e.g. group by, sort, filter etc. Tabulator can retrieve a reference to a table object by its div id, from anywhere on the page. This would allow manipulating that table directly from within template callbacks without having to send messages.

Another example is advanced (transactional) Tabulator commands which require multiple steps. It would be more complex to do it via stateful message loops, vs. direct API calls.

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [14 March 2024 19:42 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/29 "2024-03-14T19:42:30Z")

</div>

Hmmm, that makes it quite a bit trickier as that's quite anti-pattern with respect to how Node-RED operates, i.e. not sending messages in order to drive that.

You could set `id` on mounted, but then that would update every time your Dashboard mounts.

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [15 March 2024 10:07 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/30 "2024-03-15T10:07:18Z")

</div>

Thanks @joepavitt , the `ref` works beautifully!

I still have to set a unique Id to each table `div` (else the tables override each other), but don't have to worry about `getElementById()` anymore.

I'm auto-generating a random unique Id for each `div` upon mount. The user still has the ability to set a specified Id via an optional node-config property.

```auto
<template>
<div ref="tblDiv"></div>
</template>

<script>
mounted () {
   this.tblId = this.props.tblId || 'tbl'+Math.random().toString(12).substr(2, 12);
   this.$refs.tblDiv.id = this.tblId;

```

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [15 March 2024 10:34 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/31 "2024-03-15T10:34:55Z")

</div>

For what it's worth, Tabulator does allow you to pass in the actual element, not just a `#id` selector: [Vue Table / Data Grid | Tabulator](https://tabulator.info/docs/5.6/vue#vue3-options)

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [16 March 2024 11:54 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/32 "2024-03-16T11:54:34Z")

</div>

Thanks! 👍 👍 👍

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [18 March 2024 15:46 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/33 "2024-03-18T15:46:13Z")

</div>

Hi @joepavitt,  
I'm providing a configuration option for controlling multi-user behavior (for those not on flowfuse 🙂), i.e. whether a table node should be shared (replicated across users) or per-client.

In per-user mode, `msg._client.socketId` enables me to determine if the incoming message is from another client and drop such messages. However, I am concerned this may impact patterns which rely on retaining the original message (like **link-call** ).

Yet it seems like link-call knows how to handle this and doesn't timeout on missing responses from dashboard objects. In your opinion, can I rely on this link-call behavior, or add an "ignore & forward" option?

---

<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:** [18 March 2024 16:14 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/34 "2024-03-18T16:14:00Z")

</div>

Can you show us a simple example where the link call situation might occur?

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [18 March 2024 16:46 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/35 "2024-03-18T16:46:10Z")

</div>

No situation. Link-call works well. Just wanted to be reassured that I can count on this behavior, as described below:

Assum that we have a dashboard node (e.g. button) sending messages to the contrib-table node through call-link.  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/7/c/7cbd2760b08b46e4896a6f87ac71396f56bce3a2.png)

The button message is replicated by the server (with socket id) and sent to the respective table nodes in all open clients:

- If all the table nodes respond - all responses are returned to caller successfully
- If no response from any table node - single timeout
- If the table node responds only to the msg with same socket Id, its response is returned to the caller, with no timeout for the other (dropped) messages.

---

<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:** [18 March 2024 17:12 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/36 "2024-03-18T17:12:28Z")

</div>

That is an interesting usage, multiple returns from a single call of the link call node, but I can't see any reason why it would not work, providing the tabulator passes through the original message properties that tell it where to return to.

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [19 March 2024 08:41 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/37 "2024-03-19T08:41:57Z")

</div>

Thanks @Colin, I think I figured it out.  
The Link caller sets a timer and sends the message to its assigned Link-in. If the message is replicated (while retaining the return address) all the replicas return to the caller and are sent forward (the first returning message cancels the timer).

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

So no issue with multi-user dashboard nodes.

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [21 March 2024 13:24 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/38 "2024-03-21T13:24:27Z")

</div>

Hi @joepavitt , @BartButenaers and anyone else who can help,  
The development of the tabulator node progresses well and is over \>80% complete.

So far, I have done my development by modifying the `ui-example` node. I now tried to migrate it to its own new node. I have made a new clean copy of UI-example and changed the naming (from `ui-example` to `ui-tabulator` and from `UIExample` to `UITabulator`). I also changed the file names, build scripts etc.  
NPM builds the umd file with no errors, and the new node loads & shows properly in the Node-red editor.

However, the node is not showing on the dashboard, and the group comes up empty. Other than naming, I have not changed anything in the original `ui-example` code, and I made sure the node registers itself in the dashboard (in `ui-tabulator.js`).

```auto
        if (group) {
            group.register(node, config, evts)

```

Did I miss any steps in the migration?

I open the consoles of both editor and dashboard client and am not receiving any errors or exceptions. I also tried uninstalling the existing `ui-example` node (in case it clashes with the new one), but the problem persists.

---

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [21 March 2024 13:33 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/39 "2024-03-21T13:33:44Z")

</div>

The first thing I'd check is our debug screen at `http://<host>:<ip>/dashboard/_debug`

Head to the "Widgets" tab and search for your widget type, `ui-tabulator`, does it show there?

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [21 March 2024 13:49 UTC](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068/40 "2024-03-21T13:49:26Z")

</div>

Yes it shows.

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/7/27b72a230984a0bba4fcab870e4c65fe82a5f8ce.png)

Is there a channel I can communicate with you directly?

[Previous page](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068.md?page=1)

[Next page](https://discourse.nodered.org/t/using-tabulator-grids-in-dashboard-v2-0-templates/85068.md?page=3)
