How to group header like grid below in extjs:
|-------------- A1 header------------|--------------B1 Header---------------|
|----A2Header---|---A3Header---|----B2Header---|---B3Header------|
|-----A2Data------|----A3 Data------|-----B2 Data------|-----B3 Data-------|
|-----A2Data------|----A3 Data------|-----B2 Data------|-----B3 Data-------|
my code extjs:
plColModel = new Ext.grid.ColumnModel([
new Ext.grid.RowNumberer(),
{ header: "A2Header", dataIndex: 'A2Data' },
{ header: "A3Header", dataIndex: 'A3Data' },
{ header: "B2Header", dataIndex: 'B2Data' },
{ header: "B3Header", dataIndex: 'B3Data' }
]);
I remember how I've spend a lot of time trying to understand the code in the example Sencha provided for ColumnHeaderGroup. I've made a 6-level column group header several days ago and it is not that difficult.
Put all of your column headers in an object as object keys for the following headers. Last headers' followers will be the columns' properties:
var chstructure = {
'A1 header' : {
'A2Header' : {'A2Data' : {'A2Data' : {'dataIndex' : 'A2', 'width' : 100}}},
'A3Header' : {'A3Data' : {'A3Data' : {'dataIndex' : 'A3', 'width' : 100}}}
},
'B1 header' : {
'B2Header' : {'B2Data' : {'B2Data' : {'dataIndex' : 'B2', 'width' : 100}}},
'B3Header' : {'B3Data' : {'B3Data' : {'dataIndex' : 'B3', 'width' : 100}}}
}
};
You'll need some arrays to put the headers in: these arrays will be the rows in your column header group. You'll also need a fields array: it will contain the fields for your store. Don't forget to initialize some colspan variables (I'll name them len n ) that will keep count of the colspan for each column header (in this example 'A1 header' has 2 children and 'A2Header' has only 1), and some width variables (wid n ), for each header's width.
var Row1contents = [], Row2contents = [], Row3contents = [], Row4contents = [];
var len1 = 0, len2 = 0, len3=0, wid1 = 0, wid2 = 0, wid3 = 0;
var fields = [];
Now you may finally parse chstructure in order to retrieve the column headers. Use Ext.iterate for that:
Ext.iterate (chstructure, function(Row1, Row1structure){
Ext.iterate (Row1structure, function(Row2, Row2structure){
Ext.iterate (Row2structure, function(Row3, Row3structure){
Ext.iterate (Row3contents, function(Row4, Row4structure){
len1++;len2++;len3++;
wid1+=Row4structure['width'];
wid2+=Row4structure['width'];
wid3+=Row4structure['width'];
Row4contents.push({
dataIndex: Row4structure['dataIndex'],
header: Row4,
width: Row4structure['width']
});
fields.push({
type: 'int', // may be 'string'
name: Row4structure['dataIndex']
});
});
Row3contents.push({
header: Row3,
width: wid3,
colspan: len3
});
len3=wid3=0;
});
Row2contents.push({
header: Row2,
width: wid2,
colspan: len2
});
len2=wid2=0;
});
Row1contents.push({
header: Row1,
width: wid1,
colspan: len1
});
len1=wid1=0;
});
View the 4 arrays in your console and ensure they contain all data you set. The last step is to configure the grid width the ColumnHeaderGroup plugin. Use property
plugins: [new Ext.ux.grid.ColumnHeaderGroup({
rows: [Row1Group, Row2Group, Row3Group]
});
Set columns : Row4contents for your grid and fields : fields for your grid's store.
Happy coding!
refer this :
ColumnHeaderGroup
Here is one great example by Sencha
http://dev.sencha.com/deploy/ext-3.4.0/examples/pivotgrid/people.html
Related
I am new to Extjs5. I am upgrading extJs4 to ExtJs 5. I am trying to implement a groupedColumn chart but no data shows up only the axises are visible. Even I am not getting any error.
My code is as follows:
Ext.define('Result', {
extend: 'Ext.data.Model',
fields: [
{ name: 'state', type: 'string', mapping:0 },
{ name: 'product', type: 'string', mapping:1 },
{ name: 'quantity', type: 'int', mapping:2 }
]
});
var store = Ext.create('Ext.data.ArrayStore', {
model: 'Result',
groupField: 'state',
data: [
['MO','Product 1',50],
['MO','Product 2',75],
['MO','Product 3',25],
['MO','Product 4',125],
['CA','Product 1',50],
['CA','Product 2',100],
['WY','Product 1',250],
['WY','Product 2',25],
['WY','Product 3',125],
['WY','Product 4',175]
]
});
Ext.define('Ext.chart.series.AutoGroupedColumn', {
extend: 'Ext.chart.series.Bar',
type: 'autogroupedcolumn',
alias: 'series.autogroupedcolumn',
gField: null,
constructor: function( config ) {
this.callParent( arguments );
// apply any additional config supplied for this extender
Ext.apply( this, config );
var me = this,
store = me.chart.getStore(),
// get groups from store (make sure store is grouped)
groups = store.isGrouped() ? store.getGroups().items : [],
// collect all unique values for the new grouping field
groupers = store.collect( me.gField ),
// blank array to hold our new field definitions (based on groupers collected from store)
cmpFields = [];
// first off, we want the xField to be a part of our new Model definition, so add it first
cmpFields.push( {name: me.xField } );
// now loop over the groupers (unique values from our store which match the gField)
/* for( var i in groupers ) {
// for each value, add a field definition...this will give us the flat, in-record column for each group
cmpFields.push( { name: groupers[i], type: 'int' } );
}*/
for (var i = 0; i < groupers.length; i++) {
var name = groupers[i];
cmpFields.push({name:name,type:'number'});
}
// let's create a new Model definition, based on what we determined above
Ext.define('GroupedResult', {
extend: 'Ext.data.Model',
fields: cmpFields
});
// now create a new store using our new model
var newStore = Ext.create('Ext.data.Store', {
model: 'GroupedResult'
});
// now for the money-maker; loop over the current groups in our store
for( var i = 0; i < groups.length; i++ ) {
// get a sample model from the group
var curModel = groups[ i ].items[ 0 ];
// create a new instance of our new Model
var newModel = Ext.create('GroupedResult');
// set the property in the model that corresponds to our xField config
newModel.set( me.xField, curModel.get( me.xField ) );
// now loop over each of the records within the old store's current group
for( var x = 0; x < groups[ i ].items.length; x++) {
// get the record
var dataModel = groups[ i ].items[ x ];
// get the property and value that correspond to gField AND yField
var dataProperty = dataModel.get( me.gField );
var dataValue = dataModel.get( me.yField );
// update the value for the property in the Model instance
newModel.set( dataProperty, dataValue );
// add the Model instance to the new Store
newStore.add( newModel );
}
}
// now we have to fix the axes so they work
// for each axes...
me.chart.axes.every( function( item, index, len ) {
// if array of fields
if( typeof item.getFields()=='object' ) {
// loop over the axis' fields
for( var i in item.fields ) {
// if the field matches the yField config, remove the old field and replace with the grouping fields
if( item.getFields(i)==me.yField ) {
Ext.Array.erase( item.getFields(), i, 1 );
Ext.Array.insert( item.getFields(), i, groupers );
break;
}
}
}
// if simple string
else {
// if field matches the yField config, overwrite with grouping fields (string or array)
if( item.getFields()==me.yField ) {
item.setFields(groupers);
}
}
});
// set series fields and yField config to the new groupers
me.fields,me.yField = groupers;
// update chart's store config, and re-bind the store
me.chart.store = newStore;
me.chart.bindStore( me.chart.store, true );
// done!
}
})
Ext.create('Ext.chart.CartesianChart', {
renderTo: Ext.getBody(),
width: 500,
height: 300,
animate: true,
store: store,
legend: {
position: 'right'
},
axes: [
{
type: 'numeric',
position: 'left',
fields: ['quantity'],
label: {
renderer: Ext.util.Format.numberRenderer('0,0')
},
title: 'Quantity',
grid: true,
minimum: 0
},
{
type: 'category',
position: 'bottom',
fields: ['state'],
title: 'State'
}
],
series: [
{
type: 'autogroupedcolumn',
axis: 'left',
highlight: true,
xField: 'state',
yField: 'quantity',
gField: 'product'
}
]
});
I have used Ext.chart.series.Bar in place of Ext.chart.series.Column as Ext.chart.series.Column no more valid in ExtJs 5. I also have made other minor essential changes required to make my code compatible to ExtJs 5. You can also check this example on https://fiddle.sencha.com/#fiddle/hvk .
I have already spent 3 days on it. Please help!! Thanks in advance.
#Samir, If you want a Grouped Chart which is non-stacked use stacked: false property in series. Modify the code of #MonicaOlejniczak as:
legend :{
docked: right
}
series: {
.......
........
stacked: false,
}
This should solve your problem.
I have Implemented Nested Grid in Rowexpander Plugin.Now Issue is that when i am selecting any nth row of child grid then parent grid nth row also get selected . I think because both have same rowIndex.Even when i mouseover on the child grid row same mouseover effect display for parent also simultaneously.
Below is the code for Rowexpander
var expander = new Ext.ux.grid.RowExpander({
expandOnDblClick : false,
tpl : new Ext.Template('<div id="NestedGridRow-{id}"></div>'),
renderer: function(v, p, record) {
if (record.get('cmaStatus') == 'G') {
p.cellAttr = 'rowspan="2"';
return '<div class="x-grid3-row-expander"></div>';
}
},
});
expander.on('expand', expandedRow);
function expandedRow(obj, record, body, rowIndex){
//absId parameter for the http request to get the absence details.
//Use Id to give each grid a unique identifier. The Id is used in the row expander tpl.
//and in the grid.render("ID") method.
var row = "NestedGridRow-" + record.get("id");
var id2 = "mygrid-" +record.get("id");
sapid_para = record.get('sapid');
//Create the nested grid.
var gridX = new Ext.grid.GridPanel({
id:'nestedGrid',
store: storenested,
//stripeRows: true,
columns: [
{
header : "CMA Date",
width : 120,
sortable : true,
dataIndex : 'cmaDate',
},
{
header : "Source Model",
width : 120,
sortable : true,
dataIndex : 'sourceModel',
},
{
header : "Remarks",
width : 390,
sortable : true,
dataIndex : 'remarks',
}],
height: 120,
id: id2,
plugins : [editor],
renderTo: row,
stripeRows:true,
listeners: {
render: function(gridX) {
gridX.getView().el.select('.x-grid3-header').setStyle('display', 'none');
},
rowclick : function(grid,rowIndex,e) {
alert(rowIndex);
}
},
});
gridX.render(row);
//Ext.getCmp('grid_lineage').getStore().load({params:{start:0, limit:10}});
storenested.load({params:{start:0, limit:10}});
Please Help
I had the same issue. You will need to get a handle on the nested grid, and call this:
gridX.getEl().swallowEvent(['mouseover', 'mousedown', 'click', 'dblclick', 'onRowFocus']);
I think that what I'm trying to achieve is having a tree-like inside the ng-grid. I didn't found such an implementation but I'm wondering if I can use the grouping mechanism
I need to have the group header be editable in the same manner as the rows below it (see image above), with exactly the same editable cells, acting as a master row. When updating one cell from the header group should update all the cells beneath that group.
From ng-grid docs http://angular-ui.github.io/ng-grid/ :
default value for aggregateTemplate:
<div ng-click="row.toggleExpand()" ng-style="{'left': row.offsetleft}" class="ngAggregate">
<span class="ngAggregateText">{{row.label CUSTOM_FILTERS}} ({{row.totalChildren()}} {{AggItemsLabel}})</span>
<div class="{{row.aggClass()}}"></div>
</div>
Is it possible to use this option in order to render the aggregate row as I described?
The below answer/comment is related to tree like structure and not related to making aggregate row editable...
If you are looking for tree-like structure in ng-grid, then you could achieve that with the combination of ng-if, ng-click and API(s) that updates the ng-grid data option on click of a particular row. Here is a sample plnkr.
On click of a parent row, a toggle function is called to add/remove child rows in to the ng-grid data. (Refer to my plunker code for complete details)
$scope.toggleDisplay = function(iType) {
$scope.displayItemDetails[iType] = $scope.displayItemDetails[iType] ? 0 : 1;
$scope.selItems = $scope.updateTable();
};
$scope.updateTable = function() {
var selItems = [];
for (var i in $scope.allItems) {
var iType = $scope.allItems[i]["Type"];
if (angular.isUndefined($scope.displayItemDetails[iType])) {
$scope.displayItemDetails[iType] = 0;
}
if (1 == $scope.displayItemDetails[iType]) {
$scope.allItems[i]["Summary"] = '-';
} else {
$scope.allItems[i]["Summary"] = '+';
}
selItems.push($scope.allItems[i]);
if ($scope.displayItemDetails[iType]) {
for (var j in $scope.allItems[i]["Details"]) {
$scope.allItems[i]["Details"][j]["Summary"] = "";
selItems.push($scope.allItems[i]["Details"][j]);
}
}
}
return selItems;
};
$scope.gridOptions = {
data: 'selItems',
columnDefs: [{
field: 'Summary',
displayName: '',
cellTemplate: summaryCellTemplate,
width: 30
}, {
field: 'Name',
displayName: 'Name',
}, {
field: 'Type',
displayName: 'Type',
}, {
field: 'Cost',
displayName: 'Cost',
}, {
field: 'Quantity',
displayName: 'Quantity',
}],
enableCellSelection: false,
enableColumnResize: true
};
I noticed that a user cannot hide all columns in a gridpanel. It seems that the grid must at least display one column. I can imagine this is a nice feature, but it doesn't work quite as I expected when dealing with both hideable and non-hideable columns. It seems that the rule is that at least one hideable column is required to display, even if there is a non-hideable column in the grid.
It doesn't make sense to me to not allow hiding of all hideable columns when at least one non-hideable column is displayed. Is this behaviour configurable?
I created a demo based on the Stateful Array Grid Example showing the problem:
http://jsfiddle.net/p9zqK/
var grid = Ext.create('Ext.grid.Panel', {
store: store,
stateful: true,
stateId: 'stateGrid',
columns: [
{
text : 'Company',
flex : 1,
sortable : false,
hideable : false,
dataIndex: 'company'
},
{
text : 'Price',
width : 75,
sortable : true,
renderer : 'usMoney',
dataIndex: 'price'
},
...
A simple hack is to allow all columns to be hidden unconditionally (in my application I don't bother about checking whether hideable columns exist, because I know they do...)
Ext.override(Ext.grid.header.Container,
{
updateMenuDisabledState: function()
{
var me = this,
result = me.getLeafMenuItems(),
total = result.checkedCount,
items = result.items,
len = items.length,
i = 0,
rootItem = me.getMenu().child('#columnItem');
//if (total <= 1)
if (total <= 0) /* Allow all columns to be hidden unconditionally */
{
me.disableMenuItems(rootItem, Ext.ComponentQuery.query('[checked=true]', items)[0]);
}
else
{
for (; i < len; ++i)
{
me.setMenuItemState(total, rootItem, items[i]);
}
}
}
});
I use form.fields from EXTJS API. My application is totally dynamically.
It is possible to autosize combobox thanks to value which are on store ?
Or i need to make my own method... ?!
Actually, my combobox , is declared as following :
itemId : 'materialid',
xtype : 'combobox',
anchor : '35%',
store : materialstore,
id : 'Material',
queryMode: 'local',
displayField: 'data',
width : 50,
valueField: 'data',
editable : false,
grow : true,
enforceMaxLength : true,
listeners : {
render : function(me){
var obj = materialstore.findRecord('data',materialdefaultvalue);
me.setValue(obj.get('data'),obj);
}
},
padding : '0 30 0 30',
fieldLabel : 'Material',
name : 'material',
listeners : {
blur : function(me){
var fieldvalue = me.getValue();
var sel = monPretree.getView().getSelectedRecords();
for ( var i = 0 ; i < sel.length ; i++){
alert(sel[i].get('id') + ' && ' + material);
}
}
}
Thanks :)
Unfortunately not. Your best bet would be either to set a fixed width (like you have) or set it to '100%'.
A quick note for future questions: it is better to ask them over on the Sencha forums, as you will get a quicker response.