Search code examples
javascripteventsevent-handlingtabulator

Tabulator editable parameter overrides rowClick handler


Working with Tabulator 5.6.

Example of the issue

Creating an "admin mode" type interaction.

In this example, I have a table that should be editable based on a Boolean variable. The optional editing documentation has a call back function example for checking true/false of the "Editor" parameter, however the editor parameter seems to override a "rowClick" handler (I'm assuming that the editor is similar to a "cellClick" event, so you can't actually click the row once Editor is set).

My desired functionality is that the table will handle a "rowClick" event if the editable variable/parameter is false. If the editable variable is true, then it should allow the cell to be edited AND the "rowClick" handler should not be used. I would like to avoid an additional column that would hold a call to an edit function.

Using the following, the createHandlers() adds the "rowClick" handler and it works as expected.

this.columns =
            [
                {
                    title: "User",
                    field: "userId",
                    editor: "input",
                    formatter: "textarea", //Editor properties
                    validator:"required", //Require input if being editted
                    cellEdited:function(cell) {
                        cell.getElement().style.color= "#ffffff";              //CHANGE CELL WHITE FONT
                        cell.getElement().style.backgroundColor = "#e68a00";   //CHANGE CELL GOLD COLOR
                    },
}]
this.createHandlers();
private createHandlers(): void {
        this.table.on("rowClick", (e, row) => {
            this.table.selectRow(row);
            //Additional functionality, updates some child tables etc
        });
    }

When the editable parameter is added, the table shows the following behaviors.

1.) editable = true -> the cell will be selected to edit AND the "rowClick" event will occur (frustrating from a front end users perspective. 2.) editable = false -> the cell will not be editable and the "rowClick" function will NOT occur.

this.columns =
            [
                {
                    title: "User",
                    field: "userId",
                    editor: "input",
                    formatter: "textarea", //Editor properties
                    editable: true/false,
                    validator:"required", //Require input if being editted
                    cellEdited:function(cell) {
                        cell.getElement().style.color= "#ffffff";              //CHANGE CELL WHITE FONT
                        cell.getElement().style.backgroundColor = "#e68a00";   //CHANGE CELL GOLD COLOR
                    },
}]
this.createHandlers();

I've tried a couple things:

Tried to use a "cellClick" event to handle the adding/deleting of the parameter itself. It appears that the "cellClick" event occurs AFTER the editable functionality occurs, so the cell still becomes selectable to edit resulting in the same interaction as above.

let editCheck = (): boolean => this.editable;
cellClick: (e, cell) => {
                        if (editCheck()) {
                            cell.getColumn().updateDefinition({ editable: true});
                        }
                        else {
                            this.table.getColumnDefinitions().forEach(e => {
                                delete e.editable;
                            });
                            const t = cell.getRow();
                            this.table.selectRow(t);
                            //Additional functionality, updates some child tables etc
                        }
                    },

I also tried to remove the handler and re-add it as this.editable is updated, this throws an error as if the handler was not added at all OR it was overwritten by the editable callback.

private admin(): void {
        this.editable = !this.editable;
        (this.editable) ? this.table.off("rowClick") : this.createHandlers();
    }

I don't know if this means I have to re-draw the table every time the admin mode is selected (an option I'm not a fan of).

Any help is very appreciated, I've been struggling haha.


Solution

  • I was able to answer my own question.

    The solution of looping through and adding/deleting the property was correct, but in my above example, I was only adding/deleting the "editable" property. It is necessary to add/delete BOTH the "Editable" and the "Editor" property. You must then redraw the table.

    For example:

    public enableEdit(): void {
        this.editable = !this.editable; //switch boolean
        this.adminColors(this.editable); //Enable visual cue
        this.columns.forEach(e => { //add editable property
    
            if (this.editable && e?.editable != false) {
                e.editable = true;
                e.editor = "input";
            } else {
                delete e?.editable;
                delete e?.editor;
            }
        });
    
        if (this.editable) {
            // this.mT.removeHandler("rowClick");
            // this.mT.rebuildTable();
    
            this.mT.handlers = [];
            this.buildTable();
        } else {
            //this.buildTable();
            this.buildTable();
            this.createHandlers();
        }
    }
    

    So when admin mode is added, enableEdit() is called. (Any way you are calling this function is fine)

    this.columns is the array of columns fed to tabulator. If you're not assigning/storing this array, you can use something similar to the following to get your column definitions. It's a native tabulator function.

    this.table.getColumnLayout()
    

    Iterating through in the above function and adding/deleting BOTH properties and reloading the table works properly. Be sure that the columns are showing the new properties (editable, editor) prior to the redraw.

    Regarding the handlers, I found it easier to clear the handler array in the tabulator table definition. Using the "off" property was throwing an error but that could just be my implementation.

    this.table.handlers = [];