Renaming column header from column menu in Ext JS 4.1 - extjs

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

Related

Adding enabling and disabling as context menu on a grid in extjs

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.

Need to set class/id values on buttons in Extjs MessageBox

Our testing team require IDs or class values to be set on the HTML elements in our message popup boxes. This is for their automated tests.
I can pass in a class value for the dialog panel by passing in a cls value like so:
Ext.Msg.show({
title:'Reset Grid Layout',
msg: 'Are you sure that you want to reset the grid layout?',
cls:'Reset-Grid-Layout-Message',
buttons: Ext.Msg.YESNO,
fn: function (response) {
if (response == 'yes') {
}
},
icon: Ext.window.MessageBox.QUESTION
});
Now we also need it on the buttons, and also on the text being displayed. Is there some way of getting a cls value onto the buttons?
I was thinking it may be possible to expand the button parameter into something like :
buttons : [{name:'but1', cls:'asdf'}, {name:'but2', cls:'asdf2'}]
But google is not giving me back anything useful.
If your testing team uses Selenium for their automated test, adding ids/classes in every component could be difficult for both of you.
Overriding components in Ext is a good solution, but I don't recommend this because it will affect all your components. Unless you know what you're doing.
I suggest, extend Ext.window.MessageBox and generate classes for your buttons based on your parent cls.
// Put this somewhere like /custom/messagebox.js
Ext.define('App.MyMessageBox', {
extend: 'Ext.window.MessageBox'
,initConfig: function(config) {
this.callParent(arguments);
}
,makeButton: function(btnIdx) {
var me = this;
var btnId = me.buttonIds[btnIdx];
return new Ext.button.Button({
handler: me.btnCallback
,cls: me.cls + '-' + btnId
,itemId: btnId
,scope: me
,text: me.buttonText[btnId]
,minWidth: 75
});
}
});
To use:
App.Box = new App.MyMessageBox({
cls:'reset-grid-layout'
}).show({
title:'Reset Grid Layout'
,msg: 'Are you sure that you want to reset the grid layout?'
,buttons: Ext.Msg.YESNO
,icon: Ext.window.MessageBox.QUESTION
});
Your buttons will have reset-grid-layout-yes and reset-grid-layout-no class.
You can do the same with other components you have. Check out the Fiddle. https://fiddle.sencha.com/#fiddle/7qb
You should refer to the API
cls : String A CSS class string to apply to the button's main element.
Overrides: Ext.AbstractComponent.cls
You can also use the filter on right side (not the one in the right top corner). Just type cls and you will see all properties, methods and events containing cls (note that you see by default just public members, use the menu on the right of this searchfield to extend this)
Edit
If you just need it for testing purpose I would recommend to override the responsible method. This should work (untested!)
Ext.window.MessageBox.override({
buttonClasses: [
'okCls', 'yesCls', 'noCls', 'cancelCls'
],
makeButton: function(btnIdx) {
var btnId = this.buttonIds[btnIdx];
var btnCls = this.buttonClasses[btnIdx];
return new Ext.button.Button({
handler: this.btnCallback,
cls: btnCls,
itemId: btnId,
scope: this,
text: this.buttonText[btnId],
minWidth: 75
});
}
});

ExtJs bubble menu event

I have my ExtJs menu defined as follows. I have two custom methods added to my menu item 'hookMethod' and 'handlerMethod'. 'hookMethod' is added based upon some condition. I bubble the click event for individual menu items to the root menu.
Then checks if hook is defined then call 'hookMethod' else call the 'handlerMethod' directly. The problem that I am facing is that the click listener is called twice, once for menuitem and once for menu. Also, what is e argument. I was thinking it will be called only once for menu and I will have some way to retrieve the actual menu item being clicked in it.
{
xtype: "menu",
listeners: {
click: function(item, e, eopts)
{
if(item.hookMethod) {
item.hookMethod(item.handlerMethod);
}
else {
item.handlerMethod(this);
}
}
},
items: [{
xtype: "menuitem",
text: "Process Record",
bubbleEvents: ['click'],
hookMethod: function(actualMethod)
{
//do some pre-processing here and then call the actual handler
actualMethod(args)
},
handlerMethod: function(args)
{
//Do actual processing
},
}]
}
Ext.menu.Menu click( menu, item, e, eOpts ) event have four parameters.
First parameter is menu object itself.
Second item parameter is object of the menu item that was clicked. This parameter you can use for determine which item in menu was clicked.

Extjs grid column header, add dropdown menu item to specific columns

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

Ext JS 4: Show all columns in Ext.grid.Panel as custom option

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

Resources