PDA

View Full Version : Grid HeaderCt resize problem



scancubus
9 Jan 2012, 9:26 AM
Hello,

If you look at the infinite grid, or I assume any grid in this case, do the following:

Ext.ComponentQuery.query('grid')[0].headerCt.setHeight(70)

After setting the height, when you resize a column header, the underlying column does not change its size. This is new in 4.1 because I was using it fine it 4.0. I need to resize the columns because we put filters in the headers. Any Thoughts?


Thanks.

mitchellsimoens
9 Jan 2012, 9:41 AM
I'm seeing pretty much the same behavior as in 4.0.7 except in 4.1.0 it moves the rows down correctly.

Not sure if you know but you can pass a header config object to the panel:


columns : {
border : true,
height : 100,
items : [....] //array of columns
}

The columns are still small but the header container is sized. The header container uses the gridcolumn layout which is an extension of HBox. The layout is hardcoded in the header container to use align : 'stretchmax' but since you can pass a header container config you can pass in the layout. Here is an edited example:


Ext.onReady(function() {
Ext.QuickTips.init();

// sample static data for the store
var myData = [
['3m Co', 71.72, 0.02, 0.03, '9/1 12:00am'],
['Alcoa Inc', 29.01, 0.42, 1.47, '9/1 12:00am'],
['Altria Group Inc', 83.81, 0.28, 0.34, '9/1 12:00am'],
['American Express Company', 52.55, 0.01, 0.02, '9/1 12:00am'],
['American International Group, Inc.', 64.13, 0.31, 0.49, '9/1 12:00am'],
['AT&T Inc.', 31.61, -0.48, -1.54, '9/1 12:00am'],
['Boeing Co.', 75.43, 0.53, 0.71, '9/1 12:00am'],
['Caterpillar Inc.', 67.27, 0.92, 1.39, '9/1 12:00am'],
['Citigroup, Inc.', 49.37, 0.02, 0.04, '9/1 12:00am'],
['E.I. du Pont de Nemours and Company', 40.48, 0.51, 1.28, '9/1 12:00am'],
['Exxon Mobil Corp', 68.1, -0.43, -0.64, '9/1 12:00am'],
['General Electric Company', 34.14, -0.08, -0.23, '9/1 12:00am'],
['General Motors Corporation', 30.27, 1.09, 3.74, '9/1 12:00am'],
['Hewlett-Packard Co.', 36.53, -0.03, -0.08, '9/1 12:00am'],
['Honeywell Intl Inc', 38.77, 0.05, 0.13, '9/1 12:00am'],
['Intel Corporation', 19.88, 0.31, 1.58, '9/1 12:00am'],
['International Business Machines', 81.41, 0.44, 0.54, '9/1 12:00am'],
['Johnson & Johnson', 64.72, 0.06, 0.09, '9/1 12:00am'],
['JP Morgan & Chase & Co', 45.73, 0.07, 0.15, '9/1 12:00am'],
['McDonald\'s Corporation', 36.76, 0.86, 2.40, '9/1 12:00am'],
['Merck & Co., Inc.', 40.96, 0.41, 1.01, '9/1 12:00am'],
['Microsoft Corporation', 25.84, 0.14, 0.54, '9/1 12:00am'],
['Pfizer Inc', 27.96, 0.4, 1.45, '9/1 12:00am'],
['The Coca-Cola Company', 45.07, 0.26, 0.58, '9/1 12:00am'],
['The Home Depot, Inc.', 34.64, 0.35, 1.02, '9/1 12:00am'],
['The Procter & Gamble Company', 61.91, 0.01, 0.02, '9/1 12:00am'],
['United Technologies Corporation', 63.26, 0.55, 0.88, '9/1 12:00am'],
['Verizon Communications', 35.57, 0.39, 1.11, '9/1 12:00am'],
['Wal-Mart Stores, Inc.', 45.45, 0.73, 1.63, '9/1 12:00am']
];

/**
* Custom function used for column renderer
* @param {Object} val
*/
function change(val) {
if (val > 0) {
return '<span style="color:green;">' + val + '</span>';
} else if (val < 0) {
return '<span style="color:red;">' + val + '</span>';
}
return val;
}

/**
* Custom function used for column renderer
* @param {Object} val
*/
function pctChange(val) {
if (val > 0) {
return '<span style="color:green;">' + val + '%</span>';
} else if (val < 0) {
return '<span style="color:red;">' + val + '%</span>';
}
return val;
}

// create the data store
var store = Ext.create('Ext.data.ArrayStore', {
fields: [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
],
data: myData
});

// create the Grid
var grid = Ext.create('Ext.grid.Panel', {
store: store,
columns: {
border : true,
height : 100,
layout : {
type : 'gridcolumn',
availableSpaceOffset : 0,
align : 'stretch',
resetStretch : true
},
items : [
{
text : 'Company',
flex : 1,
sortable : false,
dataIndex: 'company'
},
{
text : 'Price',
width : 75,
sortable : true,
renderer : 'usMoney',
dataIndex: 'price'
},
{
text : 'Change',
width : 75,
sortable : true,
renderer : change,
dataIndex: 'change'
},
{
text : '% Change',
width : 75,
sortable : true,
renderer : pctChange,
dataIndex: 'pctChange'
},
{
text : 'Last Updated',
width : 85,
sortable : true,
renderer : Ext.util.Format.dateRenderer('m/d/Y'),
dataIndex: 'lastChange'
},
{
xtype: 'actioncolumn',
width: 50,
items: [{
icon : '../shared/icons/fam/delete.gif', // Use a URL in the icon config
tooltip: 'Sell stock',
handler: function(grid, rowIndex, colIndex) {
var rec = store.getAt(rowIndex);
alert("Sell " + rec.get('company'));
}
}, {
getClass: function(v, meta, rec) { // Or return a class from a function
if (rec.get('change') < 0) {
this.items[1].tooltip = 'Hold stock';
return 'alert-col';
} else {
this.items[1].tooltip = 'Buy stock';
return 'buy-col';
}
},
handler: function(grid, rowIndex, colIndex) {
var rec = store.getAt(rowIndex);
alert((rec.get('change') < 0 ? "Hold " : "Buy ") + rec.get('company'));
}
}]
}
]
},
height: 350,
width: 600,
title: 'Array Grid',
renderTo: Ext.getBody(),
viewConfig: {
stripeRows: true
}
});
});

This works in 4.1.0 beta 1

scancubus
9 Jan 2012, 11:43 AM
did you do grid.headerCt.setHeight(100), then drag and try and resize the header and you should see that the columns are no longer aligned with the header.

mitchellsimoens
9 Jan 2012, 11:53 AM
In my code it works with resizing columns

slemmon
9 Jan 2012, 11:59 AM
On an unrelated note, how'd you drop fields into your column headers?

scancubus
9 Jan 2012, 12:13 PM
This is a few step process, so bear with me.

In your columnModel, lets define the coupon column, as seen in the picture above. It has a min-max column filter.


{
text : '<br/>Coupon',
dataIndex : 'coupon',
width : 85,
align: 'right',
sortable: true,
hideable: true,
filter:{
filterType: 'minmax'
}
}


Then the fun begins. Go back to your grid instance, and add the following. Please note that the grid is given a internalGridId in the config. The min max column filter is created with the createMinMaxColumnFilters method.


internalGridId:1,

filterInit: function() {
Ext.log('FilterInit Started for ' + this.id);
var grid = this;
this.setUpColumFilters(grid);
grid.headerCt.doLayout();


Ext.select('.Filters'+grid.internalGridId).on('click', function(ev, target) {
ev.stopEvent();
// ev.stopPropagation();
if (!target.classList.contains('x-form-date-trigger'))
target.select();
});
this.filtersCreated=true;
},
setUpColumFilters : function(bondlist) {
var me = this;
Ext.each(bondlist.columns,function(column){
if (column.isGroupHeader){
Ext.each(column.items.items,function(column){
me.createFilter(column,bondlist.internalGridId);
});
}else{
me.createFilter(column,bondlist.internalGridId);
}

});
},
createFilter: function(column,gridId){
var me = this;
if (column.filter && !column.isCheckerHd){
var filterId = "Filter"+Ext.String.capitalize(column.dataIndex)+gridId;
if (column.filter.filterType=='single'){
me.createSingleColumnFilter(filterId, column.dataIndex, column.width-22, column.filter.maxLength,gridId);
}else if (column.filter.filterType=='minmax'){
me.createMinMaxColumnFilters(filterId,
"min"+Ext.String.capitalize(column.dataIndex),
"max"+Ext.String.capitalize(column.dataIndex),false,gridId);
}else if (column.filter.filterType=='begend'){
me.createDateFromToColumnFilters(filterId,
"beg"+Ext.String.capitalize(column.dataIndex),
"end"+Ext.String.capitalize(column.dataIndex),gridId);
}
}
this.createDateFromToColumnFilters('FilterFirstSettleDate', 'begFirstSettleDate', 'endFirstSettleDate');
},
/**
* Creates two textfields where the user specifies them to renderTo. Used in the headerCt of a grid to filter.
* @param renderTo div to render textfields to.
* @param minName Filters name for Min Value
* @param maxName Filters name for Max Value
* @param vertical {Boolean} Specifies if the filters are stacked vertically(true)
*/
createMinMaxColumnFilters : function(renderTo, minName, maxName, vertical,gridId) {
if (Ext.fly(renderTo) == null)
return false;

var minTextField = Ext.create('Ext.form.field.Text', {
name : minName,
type:'FilterTextBox',
emptyText : 'Min',
cls : 'Filters'+gridId,
width : 30
});
minTextField.on('change', this.fieldChange, this, {
buffer : 400
});
var maxTextField = Ext.create('Ext.form.field.Text', {
name : maxName,
emptyText : 'Max',
type:'FilterTextBox',
cls : 'Filters'+gridId,
width : 30
});
if (vertical == true) {
layout = '';
} else {
layout = {
type : 'hbox'
};
}
maxTextField.on('change', this.fieldChange, this, {
buffer : 400
});
Ext.create('Ext.container.Container', {
layout : layout,
renderTo : renderTo,
items : [ minTextField, {
xtype : 'label',
text : ' -',
cls : 'FilterSeperators'+gridId
}, maxTextField


]
});
}



Finally, the fields are given a fieldChange function on their change event as you can see above. This will reload the store with the passed in filter.


fieldChangeRemove : function(store, field) {
store.filters.each(function(item, index, length) {
var newField = "";
newField = field.name;
if (newField == item.property) {
store.filters.removeAt(index);
return false;
}
});
},
/**
* Adds a filter to the store of the grid when user triggers this event.
* reloads the store after with the new filter.
* @param field
* @param newValue
* @param oldValue
*/
fieldChange : function(field, newValue, oldValue) {
if (field.validate()){
var store = this.store;
// Ext.log('FieldChange Event Started');
this.fieldChangeRemove(store, field);

if (newValue != null && newValue != "") {

//For rating scores pass in the correct data index

store.filters.add({
property : field.name,
value : newValue
});

}
store.load();
}
}

slemmon
9 Jan 2012, 12:59 PM
Where are you creating the div in the column header that you'll be rendering the fields to?

scancubus
9 Jan 2012, 1:10 PM
Sorry, Cant they make the code section a bit wider? I dont know how anyone can interpret it. Anyways, our column model is generated in getColumnModel(gridId), where gridId is just something to append to the end of the div ID that it will create. We put all of this in a static class.


getColumnModel:function(gridId){
var retVal = [{
text : '<br/>Coupon',
dataIndex : 'coupon',
width : 85,
align: 'right',
sortable: true,
hideable: true,
filter:{
filterType: 'minmax'
}]; return this.addFilterDivs(retVal,gridId);
}




addFilterDivs: function(columns,gridId){
var me = this;
Ext.each(columns,function(column){
if (column.columns){
Ext.each(column.columns,function(column){
me.modifyColumnText(column,gridId);
});
}else{
me.modifyColumnText(column,gridId);
}

});

return columns;
},
modifyColumnText: function(column,gridId){
if (column.filter && !column.isCheckerHd){
var filterId = "Filter"+Ext.String.capitalize(column.dataIndex)+gridId;
var newText = column.text+" <div id="+filterId+"></div>";
column.text = newText;
}
}

scancubus
9 Jan 2012, 1:14 PM
How do you apply the loadmask on a store load/prefetch in 4.1 beta?

slemmon
9 Jan 2012, 1:52 PM
That works. Thx for the tips / code. I might see if I can drop that into a plugin.

I should probably defer the loadmask to someone smarter than me, but in case no one else pipes up:
relay the beforeload and load events to the component being loaded by the store and in the listener do setLoading() perhaps?

scancubus
9 Jan 2012, 1:57 PM
i added these overrides. The store.prefetch() does not fire a 'beforeload' event, but it fires a 'beforeprefetch'. In Ext.LoadMask, onBeforeLoad() shows a mask(potentially), and onLoad() Hides it. I also added the refresh as a StoreListener, which is new in 4.1. I believe refresh is similar to the load event, but it is fired in different situations once the data has arrived.


Ext.override(Ext.LoadMask,{
getStoreListeners: function(){
return {
beforeload: this.onBeforeLoad,
beforeprefetch:this.onBeforeLoad,
refresh:this.onLoad,
load: this.onLoad,
exception: this.onLoad
};
}
});