Repository navigation
api_methods
Static methods:
Instance methods:
- bulkDelete
- closeChildTable
- deleteRecord
- deleteRows
- deselectRow
- destroy
- editRecord
- editRecordByKey
- editRecordViaAjax
- getRowByKey
- getSelectedRows
- getSortingInfo
- hideColumn
- load
- openChildTable
- performCreate
- performDelete
- performUpdate
- recalcColumnWidths
- recalcColumnWidthsOnce
- reload
- selectRow
- setColumnVisibility
- showAddRecordForm
- showColumn
- showError
- showInfo
- showWarning
- toggleRowSelection
- updateRowData
- updateFullRowData
- Additional public methods
Waits for a field in a form to be ready, mostly used for dependant fields when they get their data from the server See the events section for examples
FTable.waitForFieldReady('myfieldname', e.form, 5000);- fieldName: The name of the field to wait for.
- form: The form element containing the field.
-
timeout (optional, default
5000): Maximum time in ms to wait.
The returned promise resolves with the field's input element. It only works for <select> elements; when form is missing or the field is not a select, the promise never resolves.
Overrides the default localization strings (see localization). Call it before creating FTable instances: every instance takes a copy of the messages when it is created, so already-created tables keep their original strings.
FTable.setMessages({ deleteText: 'Verwijderen' });do a ftable-get
const result = await FTableHttpClient.get('incidents.php', {
ids: idsjoined,
action: 'ajax_bulk_assets',
do_action,
change_location
});do a ftable-post
const result = await FTableHttpClient.post('incidents.php', {
ids: idsjoined,
action: 'ajax_bulk_assets',
do_action,
change_location
});Performs the actual create request to the createAction. This is what the "Save" button of the create form calls.
const result = await table.performCreate(data)- data: The record data to post (the field names are the parameter names).
The server response object ({ Result: 'OK', Record, Message }).
There is no method to insert a row into the table locally: after a successful create FTable calls reload(), so the new record comes from the server. If you only want to add a record to the UI without touching the server, use table.showAddRecordForm()/table.load() or add the row yourself and call table.recalcColumnWidths().
async function addRecordWithServer(data) {
try {
const result = await table.performCreate(data);
if (result.Result === 'OK') {
const record = result.Record || data;
table.emit('recordAdded', { record, serverResponse: result });
table.reload(); // brings the new record into the table
return record;
} else {
table.showError(result.Message || 'Create failed');
}
} catch (error) {
table.showError(table.options.messages.serverCommunicationError);
}
}
// Usage example:
addRecordWithServer({
name: 'John',
email: 'john@example.com'
});Deletes all currently selected rows from the server and the table (shows a confirmation dialog first, then performs a delete per selected record key).
table.bulkDelete(confirmMessage)-
confirmMessage (optional): text of the confirmation dialog, defaults to
messages.deleteConfirmation.
Closes an open child table for a table row.
table.closeChildTable(row)- row: The DOM row element.
Deletes the record of a row: shows the confirmation dialog, posts the record key to the deleteAction and removes the row (plus reloads the table when paging is enabled).
table.deleteRecord(row)-
row: The DOM row element of the record to delete (e.g. from
table.getRowByKey(42)).
const table = new FTable('#StudentTableContainer', { /*...*/ });
// asks for confirmation, then deletes record 42
table.deleteRecord(table.getRowByKey(42));To customize the confirmation dialog, use the deleteConfirmation option. To delete without any dialog/UI handling, call performDelete yourself.
Deletes the specified rows from the server and table. This method can be combined with getSelectedRows method. Thus, you can get selected rows and pass their keys to deleteRows method to delete them. Shows a confirmation dialog first.
table.deleteRows(rowkeys)- rowkeys: An array of row keys to delete.
Deselects the specified row.
table.deselectRow(row)- row: row element to deselect.
Completely removes the table from its container.
table.destroy()Forces the edit dialog of a row to open.
table.editRecord(row)Forces the edit dialog of a record to open.
table.editRecordByKey(keyFieldValue)Is simply a combo of getRowByKey and editRecord
const table = new FTable('#MyTableContainer', { /*...*/ });
// To force the editDialog to open
const hash = window.location.hash;
const match = hash.match(/edit=(\d+)/);
if (match) {
const idToEdit = match[1];
table.editRecordByKey(idToEdit);
}This example allows linking from other HTML pages to the page containing this JS with something like mypage.html#edit=123. This will then open the MyTableContainer FTable edit dialog for row with key value 123 (if the row is present, can be a problem if paging is on, but see editRecordViaAjax).
Forces the edit dialog of a record to open via AJAX.
table.editRecordViaAjax(keyFieldValue, myAjaxUrl)const table = new FTable('#MyTableContainer', { /*...*/ });
// To force the editDialog to open
const hash = window.location.hash;
const match = hash.match(/edit=(\d+)/);
if (match) {
const idToEdit = match[1];
table.editRecordViaAjax(idToEdit, myAjaxUrl);
}The myAjaxUrl call will get the name and value of the key-field passed along and should respond with something like:
//Return result to FTable
$fTableResult = [
'Result' => "OK",
'Record' => $row
];
echo json_encode($fTableResult);Resulting JSON is then something like:
{
"Result": "OK",
"Record": { "PersonId": 5, "Name": "Dan Brown", "Age": 55, "RecordDate": "/Date(1320262185197)/" }
}This example allows linking from other HTML pages to the page containing this JS with something like mypage.html#edit=123. This will then open the MyTableContainer FTable edit dialog for row with key value 123 (row content loaded via AJAX request).
Returns the DOM row element for a record via the key field's value of the record key.
table.getRowByKey(keyValue)Returns all selected rows as an array of DOM elements.
const selectedRows = table.getSelectedRows()const table = new FTable('#PersonTable', { /*...*/ });
const selectedRows = table.getSelectedRows();
selectedRows.forEach(function(row) {
const recordKey = row.dataset.recordKey; // contains the row key id
const record = row.recordData; // contains all columns
const personId = record.PersonId;
const name = record.Name;
});Returns a single localized string with the current sorting, e.g. 'Name (ascending), Age (descending)' (an empty string when the table is not sorted).
const sortingInfo = table.getSortingInfo()Makes a column hidden. A shortcut version of table.setColumnVisibility
table.hideColumn(columnName)Loads records from the server.
table.load(postData, options)- postData: Optional data to send to the server.
-
options: Optional configuration object for the load call.
-
fromPage1 (boolean): If
true, resets to page 1 before loading. Useful when changing filter criteria that may reduce the total number of pages.
-
fromPage1 (boolean): If
const table = new FTable('#PersonTable', { /*...*/ });
table.load({ CityId: 2, Name: 'Halil' });
// Reset to page 1 when applying new filters
table.load({ CityId: 5 }, { fromPage1: true });If parameters are given via the load call, they are merged with the parameters coming from the listQueryParams option; on a name collision the listQueryParams value wins (it is merged in last).
Note: The
loadcall emits arecordsLoadedevent on completion. Usetable.on('recordsLoaded', callback)to execute a callback function after loading.
Opens a child table for a table row.
table.openChildTable(row, tableOptions, onInit)- row: The DOM row element.
- tableOptions: Standard FTable options for the child table.
- onInit: Callback function called when the child table is created. It receives the child FTable instance itself.
const table = new FTable('#PersonTable', {
// ... other options
fields: {
// ... other fields
Phones: {
title: '',
width: '5%',
sorting: false,
edit: false,
create: false,
listClass: 'child-opener-image-column',
display: function (personData) {
// display must return html (it is written as innerHTML), so no click handlers here
return '<img class="child-opener-image" src="/Content/images/Misc/phone.png" ' +
'title="Edit phone numbers" data-person-id="' + personData.record.PersonId + '">';
}
}
}
});
// Open the child table when the image in the Phones column is clicked (event delegation)
table.elements.table.addEventListener('click', function (e) {
const img = e.target.closest('.child-opener-image');
if (!img) return;
const row = img.closest('tr');
const personId = img.dataset.personId;
table.openChildTable(
row,
{
title: row.recordData.Name + ' - Phone numbers',
actions: {
listAction: '/PagingPerson/PhoneList?PersonId=' + personId,
deleteAction: '/PagingPerson/DeletePhone',
updateAction: '/PagingPerson/UpdatePhone',
cloneAction: '/PagingPerson/ClonePhone',
createAction: '/PagingPerson/CreatePhone?PersonId=' + personId
},
fields: {
PhoneId: {
key: true,
create: false,
edit: false,
list: false
},
PhoneType: {
title: 'Phone type',
width: '30%',
options: { '1': 'Home phone', '2': 'Office phone', '3': 'Cell phone' }
},
Number: {
title: 'Phone Number',
width: '30%'
},
RecordDate: {
title: 'Record date',
width: '20%',
type: 'date',
dateFormat: 'dd.mm.yy',
create: false,
edit: false
}
}
},
function (childTable) { // onInit handler: receives the child FTable instance
childTable.load();
}
);
});When you want to override the default Delete action flow, you can call this method to perform the actual delete.
// Override the delete button click handler after the table is initialized
table.on('recordsLoaded', function() {
// Find all delete buttons within the table
const deleteButtons = table.elements.table.querySelectorAll('.ftable-delete-command-button');
deleteButtons.forEach(button => {
// Remove any existing click handlers (FTable's default)
const newButton = button.cloneNode(true);
button.parentNode.replaceChild(newButton, button);
// Add your custom click handler
newButton.addEventListener('click', async function(e) {
e.preventDefault();
e.stopPropagation();
// Get the row and record data
const row = this.closest('.ftable-data-row');
const record = row.recordData;
// Create your custom modal content
const modalContent = document.createElement('div');
modalContent.innerHTML = `
<p>Are you sure you want to remove ${record.XXX}?</p>
<label for="additional-info">Extra info asked:</label>
<textarea id="additional-info" name="additional_info" rows="4" style="width: 100%; margin-top: 10px;"></textarea>
`;
// Create and show the custom modal using FtableModal
const customDeleteModal = new FtableModal({
title: 'Bevestiging Verwijderen',
content: modalContent,
buttons: [
{
text: 'Cancel',
className: 'ftable-dialog-cancelbutton',
onClick: () => customDeleteModal.close()
},
{
text: 'Remove',
className: 'ftable-dialog-deletebutton',
onClick: async () => {
const additionalInfo = document.getElementById('additional-info').value;
// Prepare the data to send to the server
// The key field (e.g., 'id') is required for deletion
const deleteData = {
[table.keyField]: record[table.keyField], // Essential for deletion
additional_info: additionalInfo, // Your extra field
// You can add more fields here if needed
};
customDeleteModal.close();
try {
// Manually call the delete action with your custom data
const result = await table.performDelete(deleteData);
if (result.Result === 'OK') {
// Reload the table or remove the row manually
table.reload();
if (result.Message)
table.showInfo(result.Message);
} else {
if (result.Message)
table.showError(result.Message);
}
} catch (error) {
table.showError('Server communication error.');
console.error('Delete failed:', error);
}
}
}
]
});
customDeleteModal.create().show();
});
});
});Performs the actual update request to the updateAction. This is what the "Save" button of the edit form calls.
const result = await table.performUpdate(data)- data: The record data to post (include the key field so the server knows which record to update).
The server response object ({ Result: 'OK', Record, Message }).
async function updateRecordWithServer(key, newData) {
try {
const result = await table.performUpdate(newData);
if (result.Result === 'OK') {
const row = table.getRowByKey(key);
if (row) {
table.updateRowData(row, result.Record || newData);
table.emit('recordUpdated', { record: result.Record || newData, row, serverResponse: result });
}
table.reload();
} else {
table.showError(result.Message || 'Update failed');
}
} catch (error) {
table.showError(table.options.messages.serverCommunicationError);
}
}Recalculate the column widths when a table becomes visible. Can be useful in hidden tabs.
table.recalcColumnWidths()Recalculate the column widths once when a table becomes visible. Can be useful in hidden tabs but is only done the first time the table becomes visible.
table.recalcColumnWidthsOnce()Example usage (as used in Events Made Easy WordPress plugin):
if (target == "tab-mailings") {
// Do this only when the tab is active, to avoid doing mail lookups if not needed
// Delay the trigger to ensure the tab content is fully rendered
setTimeout(function() {
const table = new FTable('#MailingsTableContainer', { /*...*/ });
table.recalcColumnWidthsOnce();
document.getElementById('MailingsLoadRecordsButton').click(); // custom button that triggers load with extra filters set
}, 100); // Adjust the delay as necessary
}FTable holds a cache for 30 seconds by default (see the listCache option). If you do external actions and need to reload data, this function first clears the cache and then performs a load.
table.reload()The reload function takes an optional parameter to indicate that you want to keep the state of the selected rows. By default this is false, passing "true" will keep the state.
Selects the specified row.
table.selectRow(row)- row: row element to select.
Changes the visibility of a column.
table.setColumnVisibility(columnName, visibility)- columnName: The name of the column.
-
visible: A boolean:
trueshows the column,falsehides it (columns that are currently sorted or markedfixedcannot be hidden).
Programmatically opens a "create new record" form dialog.
table.showAddRecordForm(record)-
record (optional, default
{}): values to prefill the form with (this is also what the clone button uses).
Makes a column visible. A shortcut version of table.setColumnVisibility
table.showColumn(columnName)Shows the table error modal with custom content (html allowed)
table.showError(customtext)Shows the table info modal with custom content (html allowed)
table.showInfo(customtext)Shows the table warning modal with custom content (html allowed)
table.showWarning(customtext)Inverts the selection state of the specified row in the table.
table.toggleRowSelection(row)- row: A DOM row element to invert.
Updates an existing record on the table programmatically.
table.updateRowData(row, newData)-
row: The DOM row element to update (required) - e.g.
table.getRowByKey(42). - newRecord: The object containing modified keys. Only the modifications are needed and used to update the relevant column in the table.
Remark: this does not call or emit any event handlers, so if you want extra actions after calling this, you'll need to do it in your own functions.
const table = new FTable('#StudentTableContainer', { /*...*/ });
table.updateRowData(table.getRowByKey( 42 ),{
Gender: 'M',
BirthDate: '2001-11-18',
About: 'Updated this record',
});If you want to update the backend server too, use performUpdate:
async function updateRecordWithServer(key, newData) {
try {
const result = await table.performUpdate(newData);
if (result.Result === 'OK') {
const row = table.getRowByKey(key);
if (row) {
table.updateRowData(row, result.Record || newData);
table.emit('recordUpdated', { record: result.Record || newData, row, serverResponse: result });
}
} else {
table.showError(result.Message || 'Update failed');
}
} catch (error) {
table.showError(table.options.messages.serverCommunicationError);
}
}
// Usage example:
updateRecordWithServer(5, {
id: 5,
name: 'Jane',
email: 'jane@example.com'
});Does the same as updateRowData but rerenders the complete row, not just the changed fields.
table.updateFullRowData(row, newData)- row: The DOM row element to update.
- newData: The object containing the (modified) values for the row.
These methods are also part of the public API of an FTable instance:
| Method | Description |
|---|---|
table.setOption(key, value) |
Overwrites a general option at runtime (returns the instance). Only affects code that reads the option afterwards; for paging use changePageSize. |
table.getState() |
Returns a copy of the internal state (records, totalRecordCount, currentPage, isLoading, selectedRecords, sorting, searchQueries). |
table.changePage(pageNumber) |
Jumps to a page (clamped between 1 and the last page) and loads it. |
table.changePageSize(newSize) |
Sets the number of rows per page, resets to page 1, loads and saves the preference. |
table.sortByColumn(fieldName, isCtrlPressed) |
Sorts by a column programmatically (same behaviour as clicking the header). |
table.clearAllSelections() |
Deselects all rows. |
table.toggleSelectAll(selectAll) |
Selects or deselects all rows. |
table.addFilter(fieldName, value, operator) |
Stores a filter in the table state (chainable). Note: the current build only stores it - the filters are not sent to the listAction, use load(queryParams) or listQueryParams for server-side filtering. Passing an empty value removes the filter for that field. |
table.clearFilters() |
Empties the stored filters (chainable). |
table.clearListCache() |
Clears the cached list/option queries so the next load is fresh. |
table.restoreSelections() |
Re-applies the selection that was preserved by reload(true). |
table.resetSearch() |
Clears all toolbar search inputs and state, then reloads. |
table.exportToCSV(filename) |
Downloads the visible table as a CSV file (default name 'table-data.csv'). |
table.printTable() |
Opens a popup window with the table and calls print() on it. |
table.closeAllChildTables() |
Closes every open child table. |
table.addToolbarButton(options) |
Adds a toolbar button ({ text, className, id, title, onClick }) and returns it. |
table.showColumnSelectionMenu(e) |
Opens the column visibility menu (normally opened by right-clicking a header or the column select button). |
table.enableColumnReorder() |
Enables drag-and-drop column reordering (called for you during init). |
table.reorderColumnsByName(sourceField, targetField, insertAfter) |
Moves a column in the column order, emits the columnsReordered event and saves the order. |
table.resetColumnOrder() |
Restores the originally defined column order. |
table.confirm(title, message, options) |
Shows FTable's confirm dialog, resolves to true/false. Also available as FTable.confirm. |
table.alert(title, message, options) |
Shows FTable's alert dialog. Also available as FTable.alert. |
table.getKeyValue(record) |
Returns the value of the key field of a record. |
table.removeRowFromTable(row) |
Removes a row element from the DOM without touching the server. |