Creating a search-enabled multi-select feature in a Tabulator.js column

Currently, I am working on a project involving Tabulator.js and attempting to incorporate a column with a multi-select feature that includes a search option. My approach has been to utilize the Select2 library, but I have run into some challenges.

Here is the code snippet I have been using:

const tabledata = [
    {
        id: 1,
        name: "Oli Bob",
        select2: ['two', 'three']
    },
    {
        id: 2,
        name: "Mary May",
        select2: ['two']
    },
    {
        id: 3,
        name: "Christine Lobowski",
        select2: ['two']
    },
    {
        id: 4,
        name: "Brendon Philips",
        select2: ['two']
    },
    {
        id: 5,
        name: "Margret Marmajuke",
    },
];

const list = [
    {
        id: 'one',
        text: 'one'
    },
    {
        id: 'two',
        text: 'two'
    },
    {
        id: 'three',
        text: 'three'
    }
];

const select2Editor = function (cell, onRendered, success, cancel, editorParams) {
    const editor = document.createElement("select");


    onRendered(function () {
        const select_2 = $(editor);

        select_2.select2({
            data: list,
            width: '100%',
            multiple: true,
            minimumInputLength: 0,
        })

        if (typeof cell.getValue() == 'object') {
            const selectedValuesIds = cell.getValue().map(val => list.find(x => x.text == val).id)
            select_2.val(selectedValuesIds).trigger('change')
        }

        select_2.on('select2:select select2:unselect', () => {
            const data = select_2.select2('data')
            const cellValue = data.map(el => el.text)
            success(cellValue)
        });


        // $(editor).on('blur', () => cancel)

        editor.focus()
    });

    return editor;
};

const table = new Tabulator("#table", {
    // debugEventsExternal: true,
    // debugEventsInternal: true,
    height: "500px",
    data: tabledata,
    rowHeight: 32,
    columns: [
        {
            title: "Name",
            field: "name",
            width: 150
        },
        {
            title: "Select2",
            field: "select2",
            width: 300,
            editor: select2Editor,
        },
    ],
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4330262f2620377103776d726d736e31206d73">[email protected]</a>/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2c5f4940494f581e6c18021d021c015e4f021c">[email protected]</a>/dist/js/select2.min.js"></script>
<link href="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6e1a0f0c1b020f1a011c431a0f0c020b1d2e58405e405e">[email protected]</a>/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e7938685928b86938895ca9386858b8294a7d1c9d7c9d7">[email protected]</a>/dist/js/tabulator.min.js"></script>
<div id="table"></div>

I have encountered the following challenges while using this code:

  1. The process of opening the list is cumbersome as it requires clicking twice - once for the editor to appear and then again for the list to show up. This feels counterintuitive.

  2. If I click on other non-editable cells while the list is open, the focus does not shift away. I attempted to resolve this by adding "$(editor).on('blur', () => cancel)", but this causes the list not to open at all because the focus moves to the select2 element when the list appears, resulting in the editor closing.

I am exploring alternatives to simplify the implementation of this feature, potentially without relying on additional libraries. If there are any suggestions or guidance on improving my current approach using Select2, I would greatly appreciate it. Thank you!

Answer №1

Need to handle the first case? Simply utilize the open method.

The open method triggers the dropdown menu to display the available options.

select_2.select2('open');

As for the second scenario, consider using the select2:close event.

This event is fired when the dropdown is closed.

select_2.on('select2:select select2:unselect select2:close'

const tabledata = [
    {
        id: 1,
        name: "Oli Bob",
        select2: ['two', 'three']
    },
    {
        id: 2,
        name: "Mary May",
        select2: ['two']
    },
    {
        id: 3,
        name: "Christine Lobowski",
        select2: ['two']
    },
    {
        id: 4,
        name: "Brendon Philips",
        select2: ['two']
    },
    {
        id: 5,
        name: "Margret Marmajuke",
    },
];

const list = [
    {
        id: 'one',
        text: 'one'
    },
    {
        id: 'two',
        text: 'two'
    },
    {
        id: 'three',
        text: 'three'
    }
];

const select2Editor = function (cell, onRendered, success, cancel, editorParams) {
    const editor = document.createElement("select");


    onRendered(function () {
        const select_2 = $(editor);

        select_2.select2({
            data: list,
            width: '100%',
            multiple: true,
            minimumInputLength: 0,
        })

        if (typeof cell.getValue() == 'object') {
            const selectedValuesIds = cell.getValue().map(val => list.find(x => x.text == val).id)
            select_2.val(selectedValuesIds).trigger('change')
        }

        select_2.on('select2:select select2:unselect select2:close', () => {
            const data = select_2.select2('data')
            const cellValue = data.map(el => el.text)
            success(cellValue)
        });
        
        // $(editor).on('blur', () => cancel)

        editor.focus()
        select_2.select2('open');
    });

    return editor;
};

const table = new Tabulator("#table", {
    // debugEventsExternal: true,
    // debugEventsInternal: true,
    height: "500px",
    data: tabledata,
    rowHeight: 32,
    columns: [
        {
            title: "Name",
            field: "name",
            width: 150
        },
        {
            title: "Select2",
            field: "select2",
            width: 300,
            editor: select2Editor,
        },
    ],
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3c4f5950595f480e7c08120d120c114e5f120c">[email protected]</a>/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9fecfaf3fafcebaddfabb1aeb1afb2edfcb1af">[email protected]</a>/dist/js/select2.min.js"></script>
<link href="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="afdbcecddac3cedbc0dd82dbcecdc3cadcef99819f819f">[email protected]</a>/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d7a3b6b5a2bbb6a3b8a5faa3b6b5bbb2a497e1f9e7f9e7">[email protected]</a>/dist/js/tabulator.min.js"></script>
<div id="table"></div>

Answer №2

Tabulator comes equipped with a versatile multi-select editor known as the "list" editor:

To utilize it in a column, you just need to specify the editor option as list

{title:"Example", field:"example", editor:"list", editorParams:{
    values:["bob", "steve", "jim"],
    multiselect:true
})

For detailed guidance, refer to the comprehensive documentation provided in the Editor Docs, along with practical examples showcased in the Examples Section

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Challenges when it comes to exporting files using Firebase Cloud Functions

I've been working with Firebase Cloud Functions using JavaScript, but I'm encountering issues with the import and export statements. Is there a solution to replace them? const firebase = require('firebase'); const config = { apiKe ...

How can you selectively export a single function from a JavaScript file?

Within my project, I have two separate modules - one written in ts and the other in js. There is a utility within the js module that needs to be accessed by the ts module. The utility service.js looks like this: module.exports = { helloFriends: functi ...

Is there a way to remove the bold styling from text next to JavaScript?

I recently launched a website at www.mvscaccounting.com, and I added a search engine made from javascript at the bottom of the page. Next to it, I wanted to put a "all rights reserved" notice. However, whenever I try to add any text next to the search engi ...

Issues with retrieving a result object from a MySQL query in NodeJS

I've been working on creating a logging system in NodeJS with a MySQL database. To establish the connection, I use the following code: const con = mysql.createConnection({ host : 'localhost', user : 'dbuser', passwor ...

Accessing a key from an AJAX JSON response and applying it within a .each() loop in jQuery

I'm struggling with a seemingly simple task that I just can't seem to get right. My goal is to convert multiple text inputs into select fields using AJAX and jQuery. Everything works smoothly, except when trying to make the $.each function dynam ...

"Trouble arises when dealing with nested object arrays in Formik and handling changes in a child

I am struggling with passing a value to handleChange in formik validation. To address this issue, I created a component whose quantity is dynamically added based on the number of numChild. My goal is to allow users to click an icon and add any number of sk ...

Sharing data between controllers using factory in AngularJS is not supported

I attempted to share data between two controllers by using a factory. However, it seems that the data is not being shared properly between the two inputs. In the AppCtrl controller, I set Data.FirstName to be equal to lattitude. But when I switch over to ...

The display of Bootstrap Cards may become distorted when incorporating J Query

I am attempting to design a dynamic HTML page that pulls data from a JSON response using an AJAX request. My goal is to display three columns in a row, but currently I am only seeing one column per row. I would greatly appreciate any guidance on what migh ...

Tips for navigating to an external website through GraphQL

I am currently utilizing Node.js and Front-end on Next.js. I have a GraphQL server with a GetUrl method that returns a link (for example: ""). My goal is to redirect a client who made a request to that page with a Basic Auth Header. From what I understan ...

Issue: Module '/Users/MYNAME/Desktop/Projects/MYPROJECTNAME' not found

I am currently in the process of compiling Node using TypeScript, and I'm still getting acquainted with it. An issue I encountered was that my /src files were not being updated when I made changes and restarted the server. To troubleshoot, I decided ...

Tips for halting a MySQL database transaction within a NodeJS environment using expressJS

Recently, I encountered a coding challenge that involved managing a long database transaction initiated by a user. The scenario was such that the user inadvertently updated 20 million entries instead of the intended 2 million, causing a significant impact ...

You are unable to access the array beyond the scope of the function

I am encountering an issue with a function I wrote: function gotData(data){ result = data.val() const urls = Object.keys(result) .filter(key => result[key].last_res > 5) .map(key => ({url: 's/price/ ...

Troubleshooting not locating view files in ExpressJS and implementing client-side JavaScript and CSS deployment in ExpressJS

My JavaScript file is located in the same directory as my HTML file, and I am trying to render it. I'm unsure of what I may be missing. How difficult could it possibly be? var express = require('express'); var app = express(); app.engine( ...

"Troubleshooting why the jQuery Click Function is malfunctioning specifically in

Can someone help me troubleshoot this animate out script? It works fine on chrome, but not on Firefox and I can't seem to figure out why. Any suggestions? The script is designed to animate certain elements when a specific link is clicked. <scrip ...

What is the process for switching directories and renaming a file when uploading in nodeJs?

I am currently using multer and fs to handle the upload of an image file. How can I modify the directory where uploaded files are stored? Currently, all files are saved in my "routes" folder instead of the "uploads" folder created by multer. Additionally, ...

An Undefined Session: Leveraging Connect-Redis with ExpressJS and Node.js

Upon waking up this morning, I was greeted with an error message from Nodejitsu: Warning: connection.session() MemoryStore is not designed for a production environment, as it will leak memory, and will not scale past a single process. Determined to find ...

Securing specific pages in Angular front-end: A guide to implementing authentication

Interested in developing a web application using Node.js that allows users to log in (authentication). The app will have 3 non-secure pages (/home, /contact, /about) and one secure page (/admin). I've been consulting the Mean Machine book from scotch. ...

Display a hoverable button for a singular element within an array during the process of mapping through the array

const ChatWidget = () => { const bodyRef = useRef(null) const [{messages,roomMessages,roomID,socket,user}, dispatch] = useStateValue() const [dropdown, setDropdown] = useState(false) useEffect(()=>{ const setScreen = () =>{ bodyRef.cur ...

Experiencing difficulties with node and asynchronous programming

I'm attempting to use async-waterfall in order to fetch data from an API, save it as JSON, and then store it in a database. Here is a snippet of the code I have so far. Can someone assist me with this process? async.waterfall([ function getBo ...

Dynamically loading a webpage with an element roster

I have a list and I want it so that when a user clicks on the sport1 list item, results from the database table sport1 will be displayed. Similarly, if they click on the education1 list item, results from the education1 table should be shown. The issue i ...