I have a jTable with a child table for each row. On the toolbar header of the child table I have added a custom toolbar item. I want to make that toolbar item dynamic in the sense that if there are already some rows I do not want it to show. I came across a very similar query for the main toolbar "add new" button which added a function to run on recordsLoaded:
Below is my first attempt - it is just the field entry for the main table that specifies the child table. However the ".find(....)" spec will not work in my case as mine is a custom toolbar item. What do I need to put as the .find criteria?
Thanks
Dance: {
title: '',
width: '4%',
sorting: false,
create: false,
listClass: 'centreCol',
display: function(book) {
var $img = $('<img src="Images/layers.png" title="Show associated dance entries" />');
//Open child table when user clicks the image
$img.click(function() {
var thisrow = $img.closest('tr'); //Parent row
if($('#BookTableContainer').jtable('isChildRowOpen',thisrow)) { // Clicking image a second time closes the child row
$('#BookTableContainer').jtable('closeChildRow',thisrow);
} else {
currentTitleID = book.record.DanceTitleID;
$('#BookTableContainer').jtable(
'openChildTable',
thisrow,
{
title: 'Related Dance',
toolbar: {
items: [
{
icon: 'Images/add.png',
text: 'New dance',
tooltip: 'Add dance details',
click: function() { CreateDanceDialog(); }
}
]
},
actions: {
listAction: 'BookPageData.php?action=listChildDances&DanceTitleID=' + currentTitleID,
// createAction: 'dancesData.php?action=createAssignment',
// deleteAction: 'dancesData.php?action=deleteAssignment'
},
recordsLoaded: function(event, data) {
var rowCount = data.records.length;
if (rowCount>0){
$('#BookTableContainer').find('.jtable-toolbar-item.jtable-toolbar-item-add-record').remove();
}
},
fields: {
DanceID: { key: true, create: false, edit: false, list: false, visibility: 'hidden' },
DanceTitleID: { type: 'hidden', defaultValue: currentTitleID },
ChoreographerID: { title: 'Choreographer', width: '40%', options: function() { return ChoreographerOptions; } },
FormationID: { title: 'Formation', width: '30%', options: function() { return FormationOptions; } },
GenreID: { title: 'Genre', width: '30%', options: function() { return GenreOptions; } }
}
},
function(data) { data.childTable.jtable('load'); }
);
}
});
//Return image to show on the person row
return $img;
}
},
Try this
$('#BookTableContainer').find('.jtable-toolbar').remove();
Related
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.
I try to update label on menu item when I click this menu item. It should works like click->'show' label, click->'hide' label. This is my code:
const template = [{
label: 'Menu',
submenu: [{
label: 'Search',
click() {
win.webContents.executeJavaScript("showSearch()"); // it run function changeSearch() in main.js
}
},
{
label: 'Resetuj',
click() {
win.loadURL(`file://${__dirname}/index.html?del=1`);
}
},
{
label: 'Quit',
accelerator: 'Q+CmdOrCtrl+Q',
click() {
win.loadURL(`file://${__dirname}/index.html?logout=1&close=1`);
}
}]
}];
changeSearch() I tried something like this:
Menu.items[0].submenu.items[0].label = "Changed label";
I think what you are looking for is something like this:
function addMenuItems(items, position) {
const updateSearchItems = [{
label: 'newOptionDisabled',
enabled: false,
}, {
label: 'newOptionWithAction',
enabled: true,
key: 'newOptionWIthAction',
}, {
label: 'Do some stuff',
visible: false,
key: 'doSomeStuff',
click: () => {
// stuff
},
}];
items.splice.apply(items, [position, 0].concat(updateSearchItems));
}
By defining your menu items as an object that you can reference you can always modify the object later. In my example I use a addMenuItems function that enables me to specify where I want to insert these items within the existing object.
I did this to change/modify my menu item dynamically:
const menuTemplate = [{
label: 'Options',
submenu: [
{
label: 'Hide',
click() {
changeLabel('Show'); // Put logic here
}
}
]
}];
function changeLabel(label) {
menuTemplate[0].submenu[0].label = label;
// Rebuild menu
const menu = Menu.buildFromTemplate(menuTemplate);
Menu.setApplicationMenu(menu);
}
This code is not tested!
I have a Jquery jtable that has a child table. As far as I can see it is set up as per the example in the jtable demos. The main tables= (contacts) and the child tables (categories) display without any problem. My problem is that the delete action on the category child table is not posting the row key value (categoryID) as I would expect it to and I cannot see why not. The similar action on the main table posts its just fine. Note the two console.log lines in the code below that output the postData variable, the first one reports the ID of the contact table line (ID), but the second one prints an empty array instead of the CategoryID. Any help appreciated.
Thanks
function ReturnAjax(theurl, postdata, errorfn) {
return $.ajax({
url: theurl,
type: 'POST',
dataType: 'json',
data: postdata,
cache: false,
error: errorfn
});
}
$('#ContactsTableContainer').jtable({
title: 'Contacts',
paging: true,
pageSize: 30,
sorting: true,
defaultSorting: 'LastName ASC',
selecting: true,
selectOnRowClick: true,
openChildAsAccordion: true,
deleteConfirmation: false,
actions: {
listAction: function(postData, jtParams) {
console.log("ContactsTableContainer - Loading list from custom function...");
return $.Deferred(function($dfd) {
$.ajax({
url: 'ContactsData.php?action=list&jtStartIndex=' + jtParams.jtStartIndex + '&jtPageSize=' + jtParams.jtPageSize + '&jtSorting=' + jtParams.jtSorting,
type: 'POST',
dataType: 'json',
data: postData,
success: function(data) {
if(data['RowIDs']) { RowIDs = data['RowIDs'].toString().split(','); }
$dfd.resolve(data);
},
error: MyError
});
});
},
deleteAction: function(postData) {
console.log('deleting from contacts - custom function..., '+JSON.stringify(postData));
$.when(
ReturnAjax(
'ContactsData.php?action=list&ContactID='+postData['ID'],
postData,
MyError
)
).then(
function(data) {
if (data.Result != 'OK') { alert(data.Message); }
var msg = '';
var len = data.Records.length;
if(len>0) {
msg = '\t'+data.Records[0].Category;
for(var i=1 ; i<len ; i++) { msg += '\n\t'+data.Records[i].Category; }
msg = 'Contact is in the following categories\n'+msg;
}
msg += '\n\nConfirm deletion of this contact';
if(confirm(msg)) {
$.when(
ReturnAjax(
'ContactsData.php?action=delete',
postData,
MyError
)
).done(
$('#ContactsTableContainer').jtable('reload')
);
} else {
$('#ContactsTableContainer').jtable('reload'); // Had to put this here to ensure that same delete button could be used again
}
}
).fail( function() { console.log('ajax call went wrong'); } );
}, // end of delete action
}, // end of actions
fields: {
ID: {
key: true,
create: false,
edit: false,
list: false,
visibility: 'hidden'
},
Categories: {
title: '',
width: '5%',
sorting: false,
create: false,
display: function(contact) {
var $img = $('<img src="Images/layers.png" title="Show contact\'s categories" />');
//Open child table when user clicks the image
$img.click(function() {
console.log('display function (contact)..., '+JSON.stringify(contact));
$('#ContactsTableContainer').jtable(
'openChildTable',
$img.closest('tr'), //Parent row
{
title: contact.record.Name + ' - Categories',
selecting: true,
selectOnRowClick: true,
actions: {
listAction: 'ContactsData.php?action=list&ContactID=' + contact.record.ID,
deleteAction: function(postData) {
console.log('deleting from custom category function..., '+JSON.stringify(postData));
$.when(
ReturnAjax(
'ContactsData.php?action=deleteAssignment&ContactID=' + contact.record.ID,
postData,
MyError
)
).done(
$('#ContactsTableContainer').jtable('reload')
);
}
},
fields: {
CategoryID: { key: true, create: false, edit: false, list: false, visibility: 'hidden' },
ContactID: { type: 'hidden', defaultValue: contact.record.ID },
Category: { title: 'Category' }
}
},
function(data) { data.childTable.jtable('load'); }
);
});
//Return image to show on the person row
return $img;
}
},
FirstName: {
title: 'Forename',
width: '25%',
},
LastName: {
title: 'Surname',
width: '25%',
},
HomePhone: {
title: 'Phone',
width: '15%',
sorting: false,
},
Mobile: {
title: 'Mobile',
width: '15%',
sorting: false,
},
Email: {
title: 'Email',
width: '20%',
sorting: false,
},
Name: {
type: 'hidden'
},
}
});
//Load list from server
$('#ContactsTableContainer').jtable('load');
OK, I solved it, sorry to bother anyone who may have spent time looking at this. The problem was that my child table variable names were wrong they should have been category_ID and Contact_ID
I have some problems finding my selected rows in a nested JQuery JTable via a Toolbar Click.
This is my nested table which works fine:
$(document).ready(function () {
$('#TableContainer').jtable({
title: 'MyList',
sorting: true,
defaultSorting: 'list_id desc',
actions: {
listAction: 'lists_list_action.php?action=list',
updateAction: 'lists_list_action.php?action=update',
},
fields: {
list_id: { title: 'Nr.', key: true, list: true, width: '10px', listClass: 'psg_list_center' },
//CHILD TABLE "Abos"
abos: {
title: 'Abos',
width: '5%',
sorting: false,
edit: false,
create: false,
display: function (ListData) {
//Create an image that will be used to open child table
var $img = $('<img src="../../images/list_metro.png" title="manage Listabos" />');
//Open child table when user clicks the image
$img.click(function () {
$('#TableContainer').jtable('openChildTable',
$img.closest('tr'), //Parent row
{
title: 'List: ' + ListData.record.list_name,
selecting: true, //Enable selecting
multiselect: true, //Allow multiple selecting
selectingCheckboxes: true, //Show checkboxes on first column
selectOnRowClick: false, //Enable this to only select using checkboxes
actions: {
listAction: 'lists_list_action.php?action=AbosList&ListId=' + ListData.record.list_id,
deleteAction: 'lists_list_action.php?action=AbosDelete&ListId=' + ListData.record.list_id,
},
fields: {
list_id: { type: 'hidden', defaultValue: ListData.record.list_id },
person_id: { key: true, create: false, edit: false, list: false },
person_name: { title: 'Name', width: '40%' },
created_name: { title: 'created from', create: false, edit: false },
created_on: { title: 'created on', create: false, edit: false },
updated_name: { title: 'updated from', create: false, edit: false },
updated_on: { title: 'updated on', create: false, edit: false },
},
toolbar: {
items: [{
//icon: '/images/trash.png',
text: 'remove selected Abos',
click: function () {
// here i need to something like this:
alert('list_id=' + record.list_id + ', person_id=' + record.person_id);
delete_abo(record.list_id, record.person_id);
}
}]
},
}, function (data) { //opened handler
data.childTable.jtable('load');
});
});
//Return image to show on the person row
return $img;
}
},
list_name: { title: 'List Name' },
list_description: { title: 'Description', type: 'textarea' },
list_active: { title: 'activ', options: { 1: 'Yes', 0: 'No' } },
list_allow_subscribe: { title: 'Subscribe erlaubt', options: { 1: 'Yes', 0: 'No' } },
list_allow_unsubscribe: { title: 'Unsubscribe erlaubt', options: { 1: 'Yes', 0: 'No' } },
},
});
$('#TableContainer').jtable('load');
});
Can anybody help me at the toolbar-click Section, finding the selected Rows of the Child-Table?
I tried to do something like this:
click: function (ListData) {
var $selectedRows = ListData.jtable('selectedRows');
or:
click: function () {
var $selectedRows = $('#TableContainer').jtable-child-table-container.jtable('selectedRows');
$('#TableContainer').jtable('delete', $selectedRows);
}
or:
click: function () {
var $selectedRows = $('#TableContainer').jtable-child-table-container.jtable('selectedRows');
if ($selectedRows.length > 0) {
$selectedRows.each(function () {
var record = $(this).data('record');
alert('list_id=' + record.list_id + ', person_id=' + record.person_id);
//delete_abo(record.list_id, record.person_id);
});
} else {
//No rows selected
alert('please select some rows first!');
}
}
because the last part worked fine in an "not nested" part of my program,
but I did not come to an resolution anyhow...
Thanks for help!
finaly found the solution!
The Key to get the selected Rows:
var $selectedRows = $('#TableContainer>.jtable-main-container>.jtable>tbody>.jtable-child-row .jtable-row-selected');
or the whole working function:
click: function () {
var $selectedRows = $('#TableContainer>.jtable-main-container>.jtable>tbody>.jtable-child-row .jtable-row-selected');
if ($selectedRows.length > 0) {
$selectedRows.each(function () {
var record = $(this).data('record');
alert('list_id=' + record.list_id + ', person_id=' + record.person_id);
//delete_abo(record.list_id, record.person_id);
});
} else {
//No rows selected
alert('please select some rows first!');
} }
I have a grid with five columns - username, email, enabled, locked and remove.
Username, email, enabled and locked are sourced from the server. Remove is a client-side element used to indicate that a row should be removed.
I would like to either inject the default value of remove in the store on the client side as the grid content is loading, or set it as the user interacts with the CheckBox widget.
How can I catch the code which is requesting the objects from the server and add another column?
Or, is there a better way to do this.
var TrackableRest = declare([Rest, SimpleQuery, Trackable]);
var store = new TrackableRest({target: '/api/users', useRangeHeaders: true, idProperty: 'username'});
aspect.after(store, "fetch", function (deferred) {
return deferred.then(function (response) {
response.remove = false;
return json(response);
})
});
var grid = new (declare([OnDemandGrid, Selection, Editor]))({
collection: store,
className: "dgrid-autoheight",
columns: {
username: {
label: core.username
},
email: {
label: core.email
},
enabled: {
label: core.enabled,
editor: CheckBox,
editOn: "click",
sortable: false,
renderCell: libGrid.renderGridCheckbox
},
locked: {
label: core.locked,
editor: CheckBox,
editOn: "click",
sortable: false,
renderCell: libGrid.renderGridCheckbox
},
remove: {
editor: CheckBox,
editorArgs: {"checked": false},
editOn: "click",
label: core.remove,
sortable: false,
className: "remove-cb",
renderHeaderCell: function (node) {
var inp = domConstruct.create("input", {id: "cb-all", type: "checkbox"});
return inp;
},
renderCell: libGrid.renderGridCheckbox
}
},
selectionMode: "none"
}, 'grid');
In addition, I don't want to send the remove column to the server.
My final implementation was to code the remove column like so:
remove: {
editor: CheckBox,
label: core.remove,
sortable: false,
className: "remove-cb",
renderHeaderCell: function (node) {
var inp = domConstruct.create("input", {id: "cb-all", type: "checkbox"});
return inp;
}
}
The code to perform the removes is as follows:
var removeBtn = new Button({
label: core.remove
}, 'user-remove-btn');
removeBtn.startup();
removeBtn.on("click", function (event) {
var markedForDeletion = query(".dgrid-row .remove-cb input:checked", "user-grid");
if( markedForDeletion.length > 0 ) {
lib.confirmAction(core.areyousure, function () {
markedForDeletion.forEach(function (node) {
var row = grid.row(node);
store.remove(row.data.username);
});
});
}
});
Thus the remove column became a client-side only control that was handled by the grid and the event handler.