how to Cancel Edit in tabulator - tabulator

after editing data in any row how to allow the user to cancel the edited data to go back to original data ,
cannot reload the whole table as this will cancel all edited rows , i only need to cancel one row
the undo function "table.undo();" need to be called many times to undo the whole row ,is there some thing like "row.undo();"
i would like to code to look something like blow
var ivInvGRNDGrid = new Tabulator("#ivInvGRNDGrid", {
ajaxURL: "/abc/abcd/GetData",
layout: "fitColumns",
index: "id",
columns: [
{ title: "Delete", formatter: DeleteIcon, width: 40, align: "center", cellClick: function (e, cell) { ivInvGRNDDelete(cell.getRow().getData().id); }, headerSort: false },
{ title: "Cancel Edit", formatter: UndoIcon, width: 40, align: "center", cellClick: function (e, cell) { row.undo(); }, headerSort: false },
{ id: "ID", title: "#Localizer["ID"]", field: "iD", headerToolTip: "#Localizer["IDtip"]", validator: "required", editor: "number", visible: false, sorter: "number", editable: Editable },
{ id: "ItemID", title: "#Localizer["ItemID"]", field: "itemID", headerToolTip: "#Localizer["ItemIDtip"]", validator: "required", editor: "number", validator: "required", minWidth: 120, editable: Editable },
],
});

There is no row undo function i'm afraid, but you can restore the previous value of a cell by calling the restoreOldValue on the cell component. so in the cellClick function on your cancel edit row you could do something like this:
function(e, cell){
cell.getRow().getCells().forEach(function(cell){
var oldVal = cell.getOldValue();
if(oldVal !== null){
cell.restoreOldValue();
}
})
}

Related

Why are my row/cell changes in Tabulator applied to both old and new rows/cells?

I am attempting to react to a cellEdited event in Tabulator by: (a) copying the modified row to a new row; and (b) restoring the cell value in the modified row.
My Tabulator instance is coded as follows:
function TabulatorInvitees(divId, companyName) {
try {
var table = new Tabulator(divId, {
columns: [
{
title: "<div style='width:20%; float:left; text-align:left; color:blue; font-size:14px;'>Vendor Invitees</div>",
columns: [
{ title: "DbId", field: "DbId", visible: true },
{ title: "Added", field: "Added", visible: true },
{ title: "Changed", field: "Changed", visible: true },
{ title: "Marked For Exclusion", field: "MarkedForExclusion", visible: true },
{
title: "Email Address",
field: "Email",
widthGrow: 1,
responsive: 0,
hozAlign: "center",
editor: "input",
visible: true,
cellEdited: function (cell) {
// When an email address has been changed the former record needs to be marked for exclusion and a new record needs to be added.
// Step #1: Copy the edited row to a new row and modify the [DbId] and [Added] columns.
let refTable = cell.getTable();
let row = cell.getRow();
refTable.addRow({}, true).then((newRow) => {
newRow.update(row.getData()); // Paste a copy of the data from the edited row.
newRow.update({ DbId: 0, Added: true });
})
// Step #2: Restore the original value to the edited row.
cell.restoreOldValue();
}
},
{
title: "First Name",
field: "FirstName",
widthGrow: 0.5,
responsive: 1,
hozAlign: "center",
editor: "input",
visible: true,
cellEdited: function (cell) {
cell.getRow().update({ Changed: true });
}
},
{
title: "Last Name",
field: "LastName",
widthGrow: 0.5,
responsive: 1,
hozAlign: "center",
editor: "input",
visible: true,
cellEdited: function (cell) {
cell.getRow().update({ Changed: true });
}
}
]
},
{
title: tabulatorAddUserIcon(companyName),
field: "ManageRows",
widthGrow: 0.25,
responsive: 2,
hozAlign: "center",
formatter: "tickCross",
headerClick: function (e, row) {
row.getTable().addRow({ DbId: 0, Added: true }, false);
},
cellClick: function (e, cell) {
tabulatorFreezeUnfreezeDelete(cell.getRow());
}
},
],
data: [],
height: "100%",
layout: "fitColumns", // required when using 'widthGrow'
placeholder: tabulatorPlaceholder(companyName), //display message to user on empty table
reactiveData: true, //enable reactive data
responsiveLayout: "collapse",
rowContextMenu: tabulatorContextMenu(),
});
table.on("rowTapHold", function (e, row) {
// from Tabulator documentation: "The rowTapHold event is triggered when a user taps on a row on a touch display and holds their finger down for over 1 second."
//e - the tap event object
tabulatorContextMenu();
});
table.on("tableBuilt", function () {
if (companyName.length > 0) {
table.setData(getDataSync({ caseSelector: "VendorMgmt_EmployeeList", companyCode: companyName, userEmail: graphMail }));
}
else {
table.setData([]);
}
});
}
catch (error) {
console.log(error);
}
}
Specifically, any time an [Email Address] is edited the original version must be preserved and marked as excluded. My remedy is to copy the edited version of the row into a new Tabulator row then reverse the edits to the original row (thus preserving its contents).
The following screenshot shows the initial state of the Tabulator instance after data has been retrieved from a local database using the setData() method.
The following screenshot shows the original [Email Address] (jane.doe#gmail.com) having been modified (jane.doe#yahoo.com):
The anticipated behavior is that a new record will be inserted into the table (jane.doe#yahoo.com) and the edited row will be restored using the restoreOldValue() method.
By removing the restoreOldValue() method, I can readily see the contents of the modified row have been copied to a new row. So far, so good....
The new row is added with the new [Email Address], as anticipated.
My problem arises when the restoreOldValue() method is invoked on the [Email] cell of the edited row. The restored/original value is applied to both the new row and the edited row, as follows:
Instead of having a new row for "jane.doe#yahoo.com" and an original row for "jane.doe#gmail.com" I now have two rows for "jane.doe#gmail.com".
I feel as though there should be a simple fix but I have yet to find it. Any assistance is greatly appreciated.

Why is the Tabulator getRows() function not working?

This seems like the simplest of requests but I can't seem to retrieve a set of rows from a Tabulator object.
Here's the code which instantiates the Tabulator object.........
function TabulatorInvitees(divId, companyName, userEmail) {
try {
var table = new Tabulator(divId, {
columns: [
{
title: "<div style='width:20%; float:left; text-align:left; color:blue; font-size:14px;'>Vendor Invitees</div>",
columns: [
{ title: "Id", field: "Id", visible: false },
{ title: "Added", field: "Added", visible: false },
{ title: "Changed", field: "Changed", visible: false },
{ title: "MarkedForExclusion", field: "MarkedForExclusion", visible: false },
{ title: "Email Address", field: "Email", widthGrow: 1, responsive: 0, hozAlign: "center", editor: "input", visible: true },
{ title: "First Name", field: "FirstName", widthGrow: 0.5, responsive: 1, hozAlign: "center", editor: "input", visible: true },
{ title: "Last Name", field: "LastName", widthGrow: 0.5, responsive: 1, hozAlign: "center", editor: "input", visible: true }
]
},
{
title: tabulatorAddUser(companyName),
field: "ManageRows",
widthGrow: 0.25,
responsive: 2,
hozAlign: "center",
formatter: "tickCross",
headerClick: function (e, row) {
row.getTable().addRow({ Id: 0, Added: true }, false);
},
cellClick: function (e, cell) {
tabulatorFreezeUnfreezeDelete(cell.getRow());
}
},
],
data: [],
height: "100%",
layout: "fitColumns", // required when using 'widthGrow'
placeholder: tabulatorPlaceholder(companyName), //display message to user on empty table
reactiveData: true, //enable reactive data
responsiveLayout: "collapse",
rowContextMenu: tabulatorContextMenu(),
});
table.on("rowTapHold", function (e, row) {
// from Tabulator documentation: "The rowTapHold event is triggered when a user taps on a row on a touch display and holds their finger down for over 1 second."
//e - the tap event object
//row - row component
tabulatorContextMenu();
});
table.on("tableBuilt", function () {
if (companyName.length > 0) {
table.setData(getDataSync({ caseSelector: "VendorMgmt_EmployeeList", companyCode: companyName, userEmail: userEmail }));
}
else {
table.setData([]);
}
});
}
catch (error) {
console.log(error);
}
}
The setData() function makes a call to a database function which returns three rows, similar to the following:
The following JQuery function is called when a radio button is clicked....
$(".vendorStatus").click(function (e) {
const status = e.target.value;
const tbls = Tabulator.findTable("#divVendorEmployees");
const tbl = tbls[0];
const tblRows = tbl.getRows();
console.log("tbls.length", tbls.length);
console.log("tblRows", tblRows);
});
The browser console indicates a table has been found (tbls.length = 1) but the tblRows array is empty:
I see the three rows in my Tabulator but I am not able to recall them programmatically. It seems like a simple problem which should have a simple answer.
I am using the most recent version of Tabulator (v5.4).
Any assistance is greatly appreciated.
After much searching, I finally came to the realization the DOM element associated with the Tabulator instance must be managed when attempting to refresh or replace data. I've implemented a method which allows me to delete and rebuild the DOM element each time I need to save data to my database and subsequently refresh my Tabulator instance.
Here's the code...
function refreshTabulatorObject(obj) {
let parentId = obj.parentId;
let childId = obj.childId;
//Empty and remove the current version of the [Tabulator] object.
const tables = Tabulator.findTable(childId);
if (tables.length > 0) {
var table = Tabulator.findTable(childId)[0];
table.setData([]);
}
//Remove the existing <div> from the DOM.
$(childId).remove();
//Re-create the <div> element for the [Tabulator] object and append it to the DOM.
var parentDiv = document.getElementById(parentId);
parentDiv.innerHTML = "";
var childDiv = document.createElement("div");
childDiv.setAttribute("id", childId);
parentDiv.appendChild(childDiv);
//Re-create the [Tabulator] object.
TabulatorInvitees("#" + childId, obj.companyName);
}
I'm sure those of you with a more intimate knowledge of Tabulator would likely suggest a more elegant method, however, this one appears to work and I've already spent far more time on this issue that I had anticipated. Unfortunately, elegance is not a luxury I can afford at this point.
I hope this solution might be of help to some other struggling soul.

How do I programmatically change a cell value for a programmatically inserted row in Tabulator?

I have figured out how to programmatically copy and insert a new row in my Tabulator table utilizing a right-click and the rowContextMenu property; however I am having difficulty programmatically modifying data within the cells of the newly inserted row.
An abbreviated version of my Tabulator table setup code is as follows:
function TabulatorTimeSheet(divId) {
try {
var myActionContextMenu = [
{
label: "Copy & Paste Row",
action: function (e, row) {
var myTable = row.getTable();
var rowData = row.getData();
var idx = 0;
myTable.addData(rowData, false)
.then(function (newRows) {
//NOTE: The [Added] column of the new row needs to be set to "true".
newRows.forEach(newRow => {
idx = newRow.getPosition(true);
myTable.updateRow(idx, { Added: "true" });
});
myTable.redraw(true);
})
}
}
]
var table = new Tabulator(divId, {
height: "100%",
data: [],
layout: "fitDataFill",
selectable: 1,
cellEdited: function (cell) {
var myTable = cell.getTable();
var row = cell.getRow();
var rowData = row.getData();
rowData["Changed"] = "true";
},
rowContextMenu: myActionContextMenu,
columns: [
{ title: "Date Worked", field: "DateComp", responsive: 0, hozAlign: "center", sorter: "date", editor: dateEditor },
{ title: "Start Time", field: "TimeStart", responsive: 0, hozAlign: "center", sorter: "time", editor: timeEditor },
{ title: "Finish Time", field: "TimeFinish", responsive: 0, hozAlign: "center", sorter: "time", editor: timeEditor },
{ title: "Added", field: "Added", visible: true, responsive: 0, hozAlign: "center" },
{ title: "Changed", field: "Changed", visible: false, responsive: 0, hozAlign: "center" } ]
});
table.setData(myEndPointURL, { caseSelector: myCaseSelector, emplId: myEmployeeId });
}
catch (error) {
console.log(error);
}
The addData() function inserts a copy of the selected row, as expected; however, I am unable to modify the Added cell of the newly inserted row. Regardless of my efforts, I still see a blank cell.
Any assistance is greatly appreciated.
Most of your setup looks fine. Instead of doing myTable.updateRow, use newRows.update({field: 'new val'}). Because you already have the row reference, you don't need to get the id. I think that will solve your issue.
A few other things.
You are only inserting one row, so instead of myTable.addData, use myTable.addRow. Then, the return value will only be 1 row, so you don't need the forEach.
The table.redraw probably isn't necessary.
Here is a very simple example that should do all that you need it to. I omitted the context menu as it isn't relevant to the issue, but you just need to move the function into there and it should be good.
https://jsfiddle.net/nrayburn/65cngder/6/

I have a tabulator table, align

I have a tabulator table, with three columns that are align to the right, but if the "value" in the first column is "xxx", the value in the cell need to be change to be align to the left, is this possible?
var table = new Tabulator("#example_table", {
layout: "fitDataFill",
placeholder: "No Data Set Found",
columns: [{
title: "name",
field: "name",
sorter: "string",
headerFilter: "input",
headerFilterPlaceholder: "Filter Exception Name",
formatter: "label",
width: 70,
},
{
title: "name value",
field: "namevalue",
sorter: "string",
headerFilterPlaceholder: "Filter Exception Policy Data",
headerFilter: "input",
formatter: celldataswith,
align: "right"
},
{
title: "permited value",
field: "permitedvalue",
sorter: "string",
headerFilterPlaceholder: "Filter Exception Criteria",
headerFilter: "input",
formatter: celldataswith,
align: "right"
},
{
title: "breach value",
field: "breachvalue",
sorter: "string",
headerFilterPlaceholder: "Filter Exception Breach",
headerFilter: "input",
formatter: celldataswith,
align: "right"
}
],
rowFormatter: function(row, cell) {
//row - row component
var dataExceptionName = row.getData().Name;
if (dataExceptionName == "xxx") {
row.getElement().style.backgroundColor = "#A6A6DF";
**cell.getData().namevalue.style.align = "left";
cell.getData().permitedvalue.style.align = "left";
cell.getData().breachvalue.style.align = "left";**
}
},
});
You can use a custom cell formatter to achieve this, define the formatter outside the table, then reference it in the column definitions
//define formatter
var alignFormatter = function(cell, formatterParams, onRendered){
var data = cell.getData();
if(data.name === "xxx"){
cell.getElement().style.align = "left";
}else{
cell.getElement().style.align = "right";
}
}
//column definition
{title: "name value", field: "namevalue", formatter:alignFormatter},

Tabulator: How to get a column of a column group?

If you take a look at the first example at http://tabulator.info/examples/4.4#column-groups, how do I get a reference to the column "Personal Info", so I can toggle/show/hide it?
I tried it with var col = table.getColumn("Personal Info") but that did not work (as expected).
I would prefer a vanilla JS solution which uses the built-in tabulator API. But jQuery is also ok as an alternative.
Here is a jsfiddle https://jsfiddle.net/jmartsch/g7xewtf6/17/
I found out, that I can use console.log(table.getColumn('gender').getParentColumn());
This does work, but it is not very elegant. It would be nice to have a solution that directly selects the column group header.
const tabledatasimple=[{id:1,name:"Oli Bob",location:"United Kingdom",gender:"male",rating:1,col:"red",dob:"14/04/1984"},{id:2,name:"Mary May",location:"Germany",gender:"female",rating:2,col:"blue",dob:"14/05/1982"},{id:3,name:"Christine Lobowski",location:"France",gender:"female",rating:0,col:"green",dob:"22/05/1982"},{id:4,name:"Brendon Philips",location:"USA",gender:"male",rating:1,col:"orange",dob:"01/08/1980"},{id:5,name:"Margret Marmajuke",location:"Canada",gender:"female",rating:5,col:"yellow",dob:"31/01/1999"},{id:6,name:"Frank Harbours",location:"Russia",gender:"male",rating:4,col:"red",dob:"12/05/1966"},{id:7,name:"Jamie Newhart",location:"India",gender:"male",rating:3,col:"green",dob:"14/05/1985"},{id:8,name:"Gemma Jane",location:"China",gender:"female",rating:0,col:"red",dob:"22/05/1982"},{id:9,name:"Emily Sykes",location:"South Korea",gender:"female",rating:1,col:"maroon",dob:"11/11/1970"},{id:10,name:"James Newman",location:"Japan",gender:"male",rating:5,col:"red",dob:"22/03/1998"}];
const table = new Tabulator("#example-table", {
height: "311px",
data: tabledatasimple,
columnVertAlign: "bottom", //align header contents to bottom of cell
columns: [{
title: "Name",
field: "name",
width: 160
},
{ //create column group
title: "Work Info",
columns: [{
title: "Progress",
field: "progress",
align: "right",
sorter: "number",
width: 100
},
{
title: "Rating",
field: "rating",
align: "center",
width: 80
},
{
title: "Driver",
field: "car",
align: "center",
width: 80
},
],
},
{ //create column group
title: "Personal Info",
field: "pInfo",
columns: [{
title: "Gender",
field: "gender",
width: 90
},
{
title: "Favourite Color",
field: "col",
width: 140
},
{
title: "Date Of Birth",
field: "dob",
align: "center",
sorter: "date",
width: 130
},
],
},
],
});
const columns = table.getColumns(true);
doSomething = (colName) => {
columns.forEach((col) => {
if (col.getDefinition().field === colName) {
col.hide();
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/tabulator/4.4.3/js/tabulator.min.js"></script>
<link href="https://unpkg.com/tabulator-tables#4.4.1/dist/css/tabulator.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/tabulator/4.4.3/css/tabulator_modern.css" rel="stylesheet" />
<div id="example-table"></div>
<button id="hidePInfo" onclick="doSomething('pInfo')">Hide Personal Info</button>

Resources