Good grief did I go round the houses on this one:
I have a table that has one rowSelector column (called selected) and a bunch of other columns. What I want is for the row to be selected only when clicking on the "selected" column (multi-select so multiple rows are selected with single mouse click on each row) but for another action to occur when clicking on any other column (setting data in child table in this case, as it happens)
I went round and round with this and even asked chatGPT which went round in circles itself.
I tried all possible combinations of:
- selectable = true/false
- table.on(cellclick)
- table.on(rowClick)
- stopPropagation()
- toggleSelect()
- row.select()
- row.deselect()
Most of the combinations variously:
- selected the row regardless of where it was clicked
- selected only on the "selected" column but deselected all other rows
- selected only in the "selected" column but the action on the other cols didn't work
- selected the row only in the "selected" column but seemingly randomly deselected other rows that were selected (maybe)
I finally stumbled across something that works but I don't know exactly why it works when other solution don't:
var table = new Tabulator ("#table",{
virtualDom: true,
layout: "fitDataTable",
initialSort:[
{column:"id", dir:"asc"}, //sort by this first
],
placeholder: "Loading data, please wait...",
selectable: true,
columns:[
{title:"", field:"selected", headerSort:false, headerHozAlign:"center", hozAlign:"center", formatter: "rowSelection", titleFormatter: "rowSelection"},
{title:"Id", field:"id", sorter:"string", hozAlign:"center"},
{title:"Name", field:"name", sorter:"string", hozAlign:"left"},
{title:"Active", field:"running", sorter:"boolean", formatter:"tickCross", hozAlign:"center"},
{title:"OS", field:"operating system", sorter:"string", hozAlign:"center"},
{title:"Upgradable ", field:"upgrades available", sorter:"boolean", formatter:"tickCross", hozAlign:"center"},
{title:"Last Upgrade Date", field:"last upgrade date", sorter:"datetime", hozAlign:"center"},
{title:"Packages", field:"num packages", sorter:"number", hozAlign:"right"}
]
})
table.on("cellClick", function(e, cell){
var row = cell.getRow();
// Check if the clicked cell is in the "selected" column
if (cell.getField() !== "selected") {
e.stopPropagation();
// Perform actions for clicks on other columns
var rowData = row.getData();
packagesTitle.textContent = rowData["name"];
tablePackages.setData(rowData["upgradable packages"]);
}
});
table.on("rowClick", function(e, row){
if (row.isSelected()){
row.deselect();
} else {
row.select();
}
});
So, what I think is going on here is that:
- cellclick happens first and rowclick after that
- if a field other than "selected" is clicked, it stops the event propogating up to the rowclick level and does the other action
- if the "selected" field is clickedm cellclick does nothing and it bubbles up to rowclick where is selects the row if it is not already selected and deselects it otherwise
So that makes sense.
But:
- Why is the rowclick function necessary? Surely selectable = true is already an implicit rowclick response? In which case why does stopPropagation not work in ignoring the rowselection action?
- Does supplying a rowclick function essentially override the default response that selectable = true would do? It must do otherwise it would double toggle it and you would be back where you started.
- Why doesn't it work with selectable = false? Surely I can manually manage the selection.
I would have though that selectable = true would just be a shorthand for something you could do yourself but there is more going on than that.
It concerns me because I don't really understand what is going on - seems to be something not quite right under the covers here.
Can anyone shed some light on this?