Adding a column to a dstore backed dgrid - dgrid

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.

Related

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 to create a custom button in Jodit to wrap the text in a code tag?

Basically I want to be able to generate html like <code>{a: true}</code>
As far as I can tell, the button should do the same thing as the "underline" button for example, except it will wrap the text in <code> instead of <u>;
I have tried using this:
{
buttons:
'bold,strikethrough,underline,italic,eraser,|,superscript,subscript,|,ul,ol,align,|,outdent,indent,|,font,fontsize,brush,paragraph,|,image,video,table,link,|,undo,redo,\n,selectall,cut,copy,paste,copyformat,|,hr,symbol,source,fullsize,print,code',
language: lang,
placeholder,
toolbarAdaptive: false,
uploader: {
insertImageAsBase64URI: true,
},
controls: {
code: {
name: 'code',
iconURL: 'someurl.com',
tagRegExp: '_PxEgEr_/^(code)$/i',
tags: ['code'],
tooltip: 'Code',
},
},
}
The button shows up in the toolbar, but nothing happens when I click it. The documentation shows buttons that insert text, but I need a button that wraps text instead.
Ok I figured it after going through their code, it's not well documented, but this is how you do it:
{
buttons: 'blockquote,code',
controls: {
code: {
name: 'code',
iconURL: 'someiconurl.com',
tooltip: 'Insert Code Block',
exec: function (editor) {
editor.execCommand('formatBlock', false, 'code');
},
isActive: (editor, control) => {
const current = editor.s.current();
return Boolean(
current && Jodit.modules.Dom.closest(current, 'code', editor.editor)
);
},
},
blockquote: {
name: 'blockquote',
iconURL: 'someiconurl.com',
tooltip: 'Insert blockqoute',
exec: function (editor) {
editor.execCommand('formatBlock', false, 'blockquote');
},
isActive: (editor, control) => {
const current = editor.s.current();
return Boolean(
current && Jodit.modules.Dom.closest(current, 'blockquote', editor.editor)
);
},
},
},
}

jTable dynamic custom toolbar item in child table

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();

Electron - Update label in menu

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!

jtable child table not POSTing key value

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

Resources