I want to add a custom menu column for each row in the grid.
For this purpose, I created a custom menu object witth the related options to be shown in the menu as shown in the below code.
const menu = new Menu({
anchor : false,
autoShow : false,
items : [
{
icon : 'fa-thin fa-info',
cls: 'viewAssetDetails',
itemCls: 'viewAssetDetails',
text : 'View Details'
},
{
icon : 'fa-thin fa-input-text',
text : 'Rename'
},
{
icon : 'fa-thin fa-trash',
text : 'Delete'
},
{
icon : 'fa-thin fa-cloud-arrow-down',
text : 'Download'
},
],
});
I used this menu in a widget column so that the options show when I click on the icon
{
type: 'widget',
text: '',
icon: 'fal fa-ellipsis-v',
minWidth: 30,
maxWidth: 50,
htmlEncode: false,
cls: 'text-center hidden-xs',
cellCls: 'hidden-xs',
hidden: false, // Set to false to make the column initially visible
hideable: false, // Set to false to prevent the user from hiding the column
widgets : [
{
type : 'button',
flex : 1,
menu
}
]
}
There are a few issues here that I am not able to handle.
Each option which I show in the options menu needs to be shown/hidden based on the row data. e.g I should show the download option only if a particular value in that row has a certain value.
The options menu should ideally open in a downward direction as shown below
expected_menu.png (8.25 KiB) Viewed 598 times
Currently its showing like this
current_menu.png (11.87 KiB) Viewed 598 times
Thirdly, I am not able to assign a className or id to a menu item. I already have js functions added which pick up the id/class names for the menu items and attach the event to it for performing a certain action.
Also is there a way I can add cutom tags to each item div so that the click events can pick up the required data from them?
Menu appears on the side that has a room for it. In case you scroll down and it won't be the space on top, the menu will appear on bottom. Are you sure you want to force the side?
For showing/hiding menu options, I tried the render approach you mentioned. In the widgets object, there is only one item present which is the menu icon which shows up when we load the page i.e. the anchor icon.
widget_option.png (24.84 KiB) Viewed 568 times
On further investigation of this object, i found the menu items present inside the widget object in the following path
widgets[0].initialConfig.menu.initialConfig.items
I then tried setting the hidden flag for the first option i.e. View details button to true but it does not seem to do anything
The thing is I want to hide/show options in a menu based on the current row's values. For example if a row contains a column by the name of start date and I want to show a menu option only if that row's value for start date has a certain value, I should show the option in that particular row's menu. Otherwise hide it
For reference I have provided a similar implementation I want to do.
const menu = new Menu({
anchor : false,
autoShow : false,
align : 't-b',
items : [
{
icon : 'fa-thin fa-info',
text : 'View Details'
},
{
icon : 'fa-thin fa-input-text',
text : 'Rename'
},
{
icon : 'fa-thin fa-trash',
text : 'Delete'
},
{
icon : 'fa-thin fa-cloud-arrow-down',
text : 'Download'
},
{
icon : 'fa-thin fa-star',
text : 'Add to Favourites'
}
],
});
// YesNo is a custom button that toggles between Yes and No on click
class YesNo extends Widget {
static get $name() {
return 'YesNo';
}
// Factoryable type name
static get type() {
return 'yesno';
}
// Hook up a click listener during construction
construct(config) {
// Need to pass config to super (Widget) to have things set up properly
super.construct(config);
// Handle click on the element
EventHelper.on({
element : this.element,
click : 'onClick',
thisObj : this
});
}
// Always valid, this getter is required by CellEdit feature
get isValid() {
return true;
}
// Get current value
get value() {
return Boolean(this._value);
}
// Set current value, updating style
set value(value) {
this._value = value;
this.syncInputFieldValue();
}
// Required by CellEdit feature to update display value on language locale change
// Translation is added to examples/_shared/locales/*
syncInputFieldValue() {
const
{
element,
value
} = this;
if (element) {
element.classList[value ? 'add' : 'remove']('yes');
element.innerText = value ? this.L('L{Object.Yes}') : this.L('L{Object.No}');
}
}
// Html for this widget
template() {
return `<button class="yesno"></button>`;
}
// Click handler
onClick() {
this.value = !this.value;
}
}
// Register this widget type with its Factory
YesNo.initClass();
let newPlayerCount = 0;
const grid = new Grid({
appendTo : 'container',
features : {
cellEdit : true,
sort : 'name',
stripe : true
},
// Show changed cells
showDirty : true,
async validateStartDateEdit({ grid, value }) {
if (value > DateHelper.clearTime(new Date())) {
return grid.features.cellEdit.confirm({
title : 'Selected date in future',
message : 'Update field?'
});
}
return true;
},
columns : [
{ text : 'Name', field : 'name', flex : 1 },
{
text : 'Birthplace',
field : 'city',
width : '8em',
editor : { type : 'dropdown', items : DataGenerator.cities }
},
{ text : 'Team', field : 'team', flex : 1 },
{ text : 'Score', field : 'score', editor : 'number', width : '5em' },
{
text : 'Start',
id : 'start',
type : 'date',
field : 'start',
width : '9em',
finalizeCellEdit : 'up.validateStartDateEdit'
},
{ text : 'Finish (readonly)', type : 'date', field : 'finish', width : '9em', editor : false },
{ text : 'Time', id : 'time', type : 'time', field : 'time', width : '10em' },
// Column using the custom widget defined above as its editor
{
text : 'Custom', // `text` gets localized automatically, is added to examples/_shared/locales/*
field : 'done',
editor : 'yesno',
width : '5em',
renderer : ({ value }) => value ? YesNo.L('L{Object.Yes}') : YesNo.L('L{Object.No}')
},
{ type : 'percent', text : 'Percent', field : 'percent', flex : 1 },
{
type: 'widget',
text: '',
icon: 'fal fa-ellipsis-v',
minWidth: 30,
maxWidth: 50,
htmlEncode: false,
cls: 'text-center hidden-xs',
cellCls: 'hidden-xs',
hidden: false, // Set to false to make the column initially visible
hideable: false, // Set to false to prevent the user from hiding the column
widgets : [
{
type: 'button',
flex : 1,
align: {
align: 't-b'
},
menu,
},
],
renderer({ record, widgets }) {
if (record.score<=0){
widgets[0].initialConfig.menu.initialConfig.items[0].hidden =true;
}
}
}
],
data : DataGenerator.generateData(50),
listeners : {
selectionChange({ selection }) {
removeButton.disabled = !selection.length || grid.readOnly;
}
},
tbar : [
{
type : 'button',
ref : 'readOnlyButton',
text : 'Read-only',
tooltip : 'Toggles read-only mode on grid',
toggleable : true,
icon : 'b-fa-square',
pressedIcon : 'b-fa-check-square',
onToggle : ({ pressed }) => {
addButton.disabled = insertButton.disabled = grid.readOnly = pressed;
removeButton.disabled = pressed || !grid.selectedRecords.length;
}
},
{
type : 'buttongroup',
items : [
{
type : 'button',
ref : 'addButton',
icon : 'b-fa-plus-circle',
text : 'Add',
tooltip : 'Adds a new row (at bottom)',
onAction : () => {
const
counter = ++newPlayerCount,
added = grid.store.add({
name : `New player ${counter}`,
cls : `new_player_${counter}`
});
grid.selectedRecord = added[0];
}
},
{
type : 'button',
ref : 'insertButton',
icon : 'b-fa-plus-square',
text : 'Insert',
tooltip : 'Inserts a new row (at top)',
onAction : () => {
const
counter = ++newPlayerCount,
added = grid.store.insert(0, {
name : `New player ${counter}`,
cls : `new_player_${counter}`
});
grid.selectedRecord = added[0];
}
}
]
},
{
type : 'button',
ref : 'removeButton',
color : 'b-red',
icon : 'b-fa b-fa-trash',
text : 'Remove',
tooltip : 'Removes selected record(s)',
disabled : true,
onAction : () => {
const selected = grid.selectedRecords;
if (selected && selected.length) {
const
store = grid.store,
nextRecord = store.getNext(selected[selected.length - 1]),
prevRecord = store.getPrev(selected[0]);
store.remove(selected);
grid.selectedRecord = nextRecord || prevRecord;
}
}
}
]
});
const { addButton, removeButton, insertButton } = grid.widgetMap;
// Show the dirty marker
grid.store.getAt(0).score = 200;
In the above code I am trying to hide the view details button if scroe is <=0. This is just an example and each option in the menu may have a different row value its depeds on. For this reason, I need to know for which record I am rendering the menu and then be able to show/hide options accordingly.
The issue is below code does not hide that option in the menu
Thanks Márcio. I was able to implement my logic to show/hide option inside the befoeShowMenu and its working as expected. However in the onItem event for any option, I am not able to get the row data for which the option was selected. I have the item and source param both of which are MenuItem objects with no info on the row record
How can I get the curent row record in the onItem event so that I can perform the required functionalitites accordingly.
Important Note: getRecordFromElement function is not present or working in the current version of bryntum grid I am using so an alternate way to fetch the record would be appreciated. Thanks