When we have multiple parent-child grid and want to re config the grid after load call like this:
listeners: {
'afterrender': function (grid) {
var state =grid.getState();
state.columns[1].hidden= true;
grid.applyState(state);
}
}
This behaviour is even still reproducable on ExtJS 6.5.1.
For Example
https://www.sencha.com/forum/showthread.php?306941-Apply-state-after-grid-reconfigure
Here's an override I've been using to fix the hidden columns issue. I am using 6.6 so not sure if this will work in 4.4, though. Also, you may not need to suspend/resume layouts but not sure on that either.
Ext.define('MyApp.overrides.Grid', {
override: 'Ext.grid.Panel',
applyState: function () {
this.callParent(arguments);
Ext.suspendLayouts();
Ext.each(this.getColumns(), function (column) {
if (column.hidden) {
column.show();
column.hide();
}
});
Ext.resumeLayouts(true);
}
});
Well it's still an issue with applyState. When grid is having multiple hidden columns and we use applyState function it crash our grid. So we have skip the hidden property part although it's working smooth for width change , filters etc.
listeners: {
'afterrender': function (grid) {
var state =grid.getState();
state.columns[1].hidden= false;
grid.applyState(state);
grid.columns[3].hidden = true;
}
}
if you manually set hidden property of column it'll hide it.
Related
Problem:
On first display of grid hidden column all columns shrink to the left, check attached image. If I show, hide and show this column again all works just fine No matter how many hidden columns in my grid, on first display of each of the hidden columns described issue will appear.
Before:
After:
Description:
In my app I have a grid with dynamic data and I reconfigure it on its store metachange event, like this:
Ext.define('Portal.store.DynamicStore', {
extend: 'Ext.data.Store',
...
constructor: function (config) {
if (config) {
Ext.apply(this, {
...
listeners: {
metachange: function (store, meta) {
if (config.grid) {
config.grid.reconfigure(store, meta.columns);
}
}
}
});
}
this.callParent(arguments);
}
});
Worth mention that if I create simple grid with hidden columns and store with local data all works just fine.
I created a simple fiddle to illustrate described issue.
And this is my actual code.
Seems that its known bug with grid forceFit: true and hidden columns.
Here is bug report on sencha forum.
Any workarounds for this issue?
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
});
}
});
We are using fieldset in our application using extjs3.Now we are moving forward to extjs4.So beforeexpand and beforecollapse are not working in extjs4.Is there any chance to use these or else any replacement to these events.Please help me.I am searching a lot for these.
Yes, there are no such events but it's easy to create them by yourself. Here's my fieldset which extends original one and has requested events:
Ext.define('MY.fieldset', {
extend: 'Ext.form.FieldSet',
alias: 'widget.myfieldset',
initComponent: function() {
this.addEvents('beforeexpand', 'beforecollapse');
this.callParent([arguments]);
},
setExpanded: function(expanded){
var bContinue;
if (expanded)
bContinue = this.fireEvent('beforeexpand', this);
else
bContinue = this.fireEvent('beforecollapse', this);
if (bContinue !== false)
this.callParent([expanded]);
}
});
And here is working example.
i want to change a tooltip's position to show it upon a button. I tried the method below as mentioned in ExtJs's forum. It doesn't work, i can't override the getTargetXY method, the tooltip is shown always in the same position. Do you have any solution ?
this.desktopButton = new Ext.Button({
icon: "arrow_in.png",
scope: this,
handler: this.desktopButtonHandler,
tooltip: new Ext.ToolTip({
text: 'Message',
getTargetXY: function () {
return [100, 100];
}
})
});
Ext elements can only be passed configuration options as specified in the documentation; getTargetXY is not one of those options.
If you want to override that method, you have two choices:
Override all Ext Tooltips to use your new function
Extend the existing Tooltip class to support overriding that method
I would not recommend overriding the method, as that could have other consequences. I will, however, explain how to do both.
To override the tooltip:
Ext.override(Ext.Tooltip, {
getTargetXY: function() {
return [100, 100]
}
});
To extend the tooltip:
MyToolTip = Ext.Extend(Ext.Tooltip, {
constructor: function(config) {
var config = config || {};
if (config.getTargetXY) {
this.getTargetXY = config.getTargetXY;
}
MyToolTip.superclass.constructor.call(this, config);
}
});
Note that setting 'targetXY' may prove unhelpful, as Ext JS may override this setting (depending on the view size).
Overriding the "showAt" method can prevent this:
showAt:function() {
var xy = [this.getTargetXY()[0],this.getTargetXY()[1]-this.height]
MyTooltip.superclass.showAt.call(this, xy);
}
I'm adding a custom context menu to a TreePanel.
This was all working when I had a separate function for the context menu, but I was having problems where the context menu items would end up doubled/tripling up if I clicked on one of the options and then viewed the context menu again.
I had a look around for other contextmenu examples and came up with this one by Aaron Conran I pretty much "stole" it wholesale with a few additions, tacking the function directly into the Ext.ext.treePanel config. This gave me an error about "oe is undefined" which seemed to refer to "contextmenu: this.onContextMenu" in the tree config.
I figured it was probably something to do with the way I was defining all of this, so I decided to look at extending Ext.ext.TreePanel with my function in it as a learning exercise as much as anything.
Unfortunately, having managed to sort out extending TreePanel I'm now back to getting "oe is undefined" when the page tries to build the TreePanel. I've had a look around and I'm not really sure whats causing the problem, so any help or suggestions would be greatly appreciated.
Here is the code that is used to define/build the tree panel. I hope its not too horrible.
siteTree = Ext.extend(Ext.tree.TreePanel,{
constructor : function(config){
siteTree.superclass.constructor.call(this, config);
},
onContextMenu: function(n,e){
if (!this.contextMenu){
console.log('treeContextMenu',n,e);
if (n.parentNode.id == 'treeroot'){
var menuitems = [{text:'Add Child',id:'child'}];
} else {
var menuitems =
[{text:'Add Child',id:'child'},
{text:'Add Above',id:'above'},
{text:'Add Below',id:'below'}];
}
this.contextMenu = new Ext.menu.Menu({
id:'treeContextMenu',
defaults :{
handler : treeContextClick,
fqResourceURL : n.id
},
items : menuitems
});
}
var xy = e.getXY();
this.contextMenu.showAt(xy);
}
});
var treePanel = new siteTree({
id: 'tree-panel',
title : 'Site Tree',
region : 'center',
height : 300,
minSize: 150,
autoScroll: true,
// tree-specific configs:
rootVisible: false,
lines: false,
singleExpand: true,
useArrows: true,
dataUrl:'admin.page.getSiteTreeChildren?'+queryString,
root: {
id: 'treeroot',
nodeType: 'async',
text: 'nowt here',
draggable: false
},
listeners:{
contextmenu: this.onContextMenu
}
});
As a total aside; Is there a better way to do this in my context menu function?
if (n.parentNode.id == 'treeroot') {
Basically, if the clicked node is the top level I only want to give the user an add Child option, not add above/below.
Thanks in advance for your help
In your instantiation of your siteTree class you have:
listeners: {
contextmenu: this.onContextMenu
}
However, at the time of the instantiation this.onContextMenu is not pointing to the onContextMenu method you defined in siteTree.
One way of fixing it is to call the method from within a wrapper function:
listeners: {
contextmenu: function() {
this.onContextMenu();
}
}
Assuming you don't override the scope in the listeners config 'this' will be pointing to the siteTree instance at the time the listener is executed.
However, since you are already defining the context menu in the siteTree class, you may as well define the listener there:
constructor: function( config ) {
siteTree.superclass.constructor.call(this, config);
this.on('contextmenu', this.onContextMenu);
}
Ensuring the context menu is removed with the tree is also a good idea. This makes your siteTree definition:
var siteTree = Ext.extend(Ext.tree.TreePanel, {
constructor: function( config ) {
siteTree.superclass.constructor.call(this, config);
this.on('contextmenu', this.onContextMenu);
this.on('beforedestroy', this.onBeforeDestroy);
},
onContextMenu: function( node, event ) {
/* create and show this.contextMenu as needed */
},
onBeforeDestroy: function() {
if ( this.contextMenu ) {
this.contextMenu.destroy();
delete this.contextMenu;
}
}
});
I had this problem yesterday. The issue with the duplicate and triplicate items in the context menu is due to extjs adding multiple elements to the page with the same ID. Each time you call this.contextMenu.showAt(xy) you are adding a div with the ID 'treeContextMenu' to the page. Most browsers, IE especially, deal with this poorly. The solution is to remove the old context menu before adding the new one.
Here is an abridged version of my code:
var old = Ext.get("nodeContextMenu");
if(!Ext.isEmpty(old)) {
old.remove();
}
var menu = new Ext.menu.Menu({
id:'nodeContextMenu',
shadow:'drop',
items: [ ... ]
});
menu.showAt(e.xy);
I suggest never using hardcoded IDs. #aplumb suggests cleaning the DOM to reuse an existing ID. OK, but I suggest you cleanup the DOM when you no longer need the widgets/elements in the DOM and you should never reuse an ID.
var someId = Ext.id( null, 'myWidgetId' );
var someElement = new SuperWidget({
id: someId,
...
});
Just to add to owlness's answer
This bit here:
listeners: {
contextmenu: this.onContextMenu
}
Gets executed when the javascript file is loaded. this at that stage is most likely pointing to the window object.
A simple way to fix it is adding the listener on hide event of context menu, so you destroy him.
new Ext.menu.Menu(
{
items:[...],
listeners: { hide: function(mn){ mn.destroy(); } }
}
).show(node.ui.getAnchor());
;)