I'm trying to add a button to the column header drop-down menus in my grid. However, I only want to add it to columns with certain itemId. So far I've got it working to add the button to all columns, see code below. I dont see where I could check each column's itemId though, it doesn't seem to iterate through the columns. Is there any workaround for this? Thank you!
items:[{
region:'center',
xtype:'grid',
columns:{
items: COLUMNS, //defined in index.php
},
store:'Items',
selType: 'checkboxmodel',
listeners: {
afterrender: function() {
var menu = Ext.ComponentQuery.query('grid')[0].headerCt.getMenu();
menu.add([{
text: 'edit',
handler: function() {
console.log("clicked button");
}
}]);
}
}
}],
The grid column menu exists in one instance which is shared for all columns. Because of this you can not add menu item only for one column.
However you can show/hide menu item in this menu for specific column. You can use menu beforeshow event and get information about column from menu.activeHeader property:
listeners: {
afterrender: function(c) {
var menu = c.headerCt.getMenu();
// add menu item into the menu and store its reference
var menuItem = menu.add({
text: 'edit',
handler: function() {
console.log("clicked button");
}
});
// add listener for beforeshow menu event
menu.on('beforeshow', function() {
// get data index of column for which menu will be displayed
var currentDataIndex = menu.activeHeader.dataIndex;
// show/hide menu item in the menu
if (currentDataIndex === 'name') {
menuItem.show();
} else {
menuItem.hide();
}
});
}
}
Fiddle with live example: https://fiddle.sencha.com/#fiddle/3fm
Related
Hi I have added one context menu on my grid which will perform the enable and disable functionality for selected row. I am new to ExtJs. I have added below listener for the grid. How to add enable and disable functionality for the grid row?
listeners: {
itemcontextmenu: function (grid, record, item, index, e) {
var contextMenu = Ext.create('Ext.menu.Menu', {
controller: 'grid-controller',
width: 165,
plain: true,
items: [{
text: 'Disable',
listeners: {
click: {fn: 'disable', extra: record}
},
}]
});
e.stopEvent();
contextMenu.showAt(e.getXY());
}
}
This is not a copy-paste answer, but going through the following steps with doing your own research you can solve your problem.
1. Create the context menu only once and destroy it
In you code, the context menu is created every time when the user opens up the menu on the grid. This is not good. Instead, create the context menu only once when the grid is created, and destroy it when the grid is destroyed. Something like this:
Ext.define('MyGrid', {
extend: 'Ext.grid.Panel',
initComponent : function() {
this.callParent();
this.MyMenu = Ext.create('Ext.menu.Menu', {
items: [...]
});
this.on({
scope : this,
itemcontextmenu : this.onItemContextMenu
});
},
onDestroy : function() {
if (this.MyMenu) {
this.MyMenu.destroy();
}
},
onItemContextMenu : function(view, rec, item,index, event) {
event.stopEvent();
this.MyMenu.showAt(event.getXY());
}
});
2. Store enabled / disabled state in the record
For the next step to work, records in your grid must contain whether the corresponding row is enabled or disabled. In the context menu, when user selects enabled / disabled, store this status like this, get record of the row where the context menu was displayed from:
record.set('myDisabledState', true); // or false
It is important to store the disabled state (and not enabled), because when your grid initially is rendered, these values won't be in the records, so record.get('myDisabledState') will evaluate to FALSE, and that is the desired behaviour, if you want to start with every row being able to be selected.
3. Disable selection
Now you can add a beforeselect listener to your grid, see documentation. This listeners receives record as parameter, and if you return false from this listener, the selection will be canceled. So in this listener simply add:
listeners: {
beforeselect: function ( grid, record, index, eOpts ) {
return !record.get('myDisabledState');
}
}
4. Apply formatting - OPTIONAL
It is likely that you want to add different formatting for disabled rows, for example grey colour. The easiest way to do it is to add a custom CSS style to your Application.scss file:
.my-disabled-row .x-grid-cell-inner {
color: gray;
}
Finally add getRowClass configuration to your grid, it will receive the current record being rendered, and you can return the above custom CSS style when the row is disabled:
Ext.define('MyGrid', {
// your grid definition
,
viewConfig: {
getRowClass: function (record, rowIndex, rowParams, store) {
if (record.get('myDisabledState')) {
return "my-disabled-row";
}
}
}
});
In this last part, when row is not disabled, it will return nothing, so default formatting will be used.
I am trying to create a grid using extjs 4.2.2. The grid contains several rows, if I click one row, then pops up another page which displays the detail info of that row.
The grid is in a panel, so the view code is:
Ext.define("Application.view.foo.Panel", {
extend: "Ext.panel.Panel",
cls: 'foo.panel'
...
items: [
{
itemId: "foo-bar",
xtype: "grid",
...
,selType: 'checkboxmodel'
,columns: [
xtype: 'templatecolumn'
and the code of listening row select event in controller is like:
"panel[cls~=foo.panel] #foo-bar": {
select: function(selectionModel, record, index) { .... }
Now, I am going to add check box for each row in order to mass edit, I added selType: 'checkboxmodel', but the problem is that I cannot click the check box: if I click the box, it goes the the detail page, not just being 'checked', cuz the code in controller listens that 'row click' event.
Is there any suggestions to implement it? Thanks in advance.
I would suggest to change your row click listener to view row details with action column.
{
xtype:'actioncolumn',
width:50,
items: [{
// Url is just for example (not working)
icon: 'extjs/examples/shared/icons/fam/showDetails.png', // Use a URL in the icon config
tooltip: 'Show details',
handler: function(grid, rowIndex, colIndex) {
var rec = grid.getStore().getAt(rowIndex);
// do your functionality here...
}
}
In every row will appear an icon, and then you will have possibility to multiselect rows and to look details of every row as well. Hope that helps.
Try to listen on cellclick event instead.
cellclick: function(view, td, cellIndex, record, tr, rowIndex, e, eOpts) {
if(cellIndex != your_checkbox_column) {
//do your info page stuff here
}
}
Is there a function that can be called on an Ext.grid.Panel in ExtJS that will make all columns visible, if some of them are hidden by default? Whenever an end-user needs to show the hidden columns, they need to click each column. Below, I have some code to add a custom menu option when you select a field header. I'd like to execute this function so all columns show.
As an example below, I have 'Project ID' and 'User Created' hidden by default. By choosing 'Select All Columns' would turn those columns on, so they show in the list view.
listeners: {
...
},
afterrender: function() {
var menu = this.headerCt.getMenu();
menu.add([{
text: 'Select All Columns',
handler: function() {
var columnDataIndex = menu.activeHeader.dataIndex;
alert('custom item for column "'+columnDataIndex+'" was pressed');
}
}]);
}
}
});
===========================
Answer (with code):
Here's what I decided to do based on Eric's code below, since hiding all columns was silly.
afterrender: function () {
var menu = this.headerCt.getMenu();
menu.add([{
text: 'Show All Columns',
handler: function () {
var columnDataIndex = menu.activeHeader.dataIndex;
Ext.each(grid.headerCt.getGridColumns(), function (column) {
column.show();
});
}
}]);
menu.add([{
text: 'Hide All Columns Except This',
handler: function () {
var columnDataIndex = menu.activeHeader.dataIndex;
alert(columnDataIndex);
Ext.each(grid.headerCt.getGridColumns(), function (column) {
if (column.dataIndex != columnDataIndex) {
column.hide();
}
});
}
}]);
}
If you don't need any special logic, you could try something like this:
Ext.each(grid.headerCt.getGridColumns(), function(column){
column.show();
});
I had to do this also and at first tried to implement a solution just like Eric's but it produced major lag issues on slower computers. It does a full component layout on the grid after each column is shown.
I circumvented that with this:
grid.suspendLayout = true;
Ext.each(grid.headerCt.getGridColumns(), function(column) {
column.show();
});
grid.suspendLayout = false;
grid.doComponentLayout();
Is it possible add an item to this menu in order to rename the column header?
The question seems kind of vague and I believe the image attached is throwing me off.
Customizing a grid header menu (Answer)..
See either answer.
My final product I have even customized my answer further:
initComponent: function () {
this.callParent(arguments);
this.headerCt.on('headerclick', function (header, column, event, html) {
if (column.xtype == 'rownumberer') {
return false;
};
header.showMenuBy(column.el.dom, column);
}, this);
this.headerCt.on('menucreate', function (header, column, event, html) {
var menu = header.getMenu();
this.createHeaderMenu(menu);
}, this);
},
createHeaderMenu: function (menu) {
menu.removeAll();
// simulate header menu to be plain (menu is already created at this point)
menu.addCls(Ext.baseCSSPrefix + 'menu-plain');
menu.name = 'report_data_header_menu';
menu.add({
name: 'sort_asc',
text: 'Sort Ascending'
}, {
name: 'sort_desc',
text: 'Sort Descending'
}, {
name: 'remove_column',
text: 'Remove'
});
}
You should be able to do it.
Add a listener on the 'menucreate' event on the Ext.grid.header.Container object. This delegate will pass you the reference of the menu then you can manipulate the Menu.
example
var gridHeader = gridPanelInstance.getView().headerCt; //return the Header Container
gridHeader.on('menucreate', function(gridHeaderContainer, menu, option) {
// do whatever you want with the menu here... eg: add/remove/ edit menu item
});
I created two tab panels and each panel has a grid.
Listener for Grid A:
Ext.getCmp('AGrid').addListener("rowcontextmenu", function menus(grid, rowIndex, e) {
if (!grid.contextMenu) {
grid.contextMenu = new Ext.menu.Menu({
autoDestroy: false,
items: [{ id: 'view', text: 'View Content'}],
currentRowIndex: rowIndex,
listeners: {
itemclick: function (item) {
switch (item.id) {
case 'view':
viewEmailClick(grid.getStore().getAt(this.currentRowIndex).data);
break;
}
}
}
});
}
this.contextMenu.currentRowIndex = rowIndex;
e.stopEvent(); // this stops the browser context menu and allows the default grid
// show the row context menu here
this.contextMenu.showAt(e.xy);
});
Listener for Grid B:
Ext.getCmp('BGrid').addListener("rowcontextmenu", function menus(grid, rowIndex, e) {
if (!grid.contextMenu) {
grid.contextMenu = new Ext.menu.Menu({
autoDestroy: false,
items: [{ id: 'view', text: 'View Task'}],
currentRowIndex: rowIndex,
listeners: {
itemclick: function (item) {
switch (item.id) {
case 'view':
viewTicketClick(grid.getStore().getAt(this.currentRowIndex).data);
break;
}
}
}
});
}
this.contextMenu.currentRowIndex = rowIndex;
e.stopEvent(); // this stops the browser context menu and allows the default grid
// show the row context menu here
this.contextMenu.showAt(e.xy);
});
When I right click on it Grid A works fine, and then right click on Grid B rowcontext menu is not working (just shows small gray dot).
After I turn back to Grid A and right click, it shows two rowcontext menus on Grid A:
If I right click on B grid and A grid right click (nothing shows) after turn back to B grid
it show rowcontext menu which contains two lists (reverse order) on Grid B.
Why this kind of things happen?
How can I show properly each grid row context menu?
It seems you pass the same grid variable to both listeners.
This problem is caused by parameter grid or grid.contextmenu obviously.
I found the answer.
The problem is caused by the follwing line.
items: [{ id: 'view', text: 'View Task'}]
I used same context menu id 'view'.
After those name changed like the followings
items: [{ id: 'viewTask', text: 'View Task'}]
items: [{ id: 'viewContent', text: 'View Content'}]
it works perfect.