PDA

View Full Version : Its.grid.column.Component



vietits
15 Jan 2012, 6:14 AM
This component allows you to render a component or a series of components in one or more grid cells. Document and guide how to use are included in the component source code.

Latest version: 2.3 (released on 2012-05-05)

Ext compatible versions: Ext 4.0.7, Ext 4.1.0-rc3, Ext 4.1.0-gpl.

Below is the screenshot of grid using this component to render some kinds of components, such as: chart, combobox, spinner, date picker, checkbox, button.

30734

Change log
2012-01-14: Release version 1.0
2012-01-24: Release version 2.0 with the following updates:

Remove relayEvents, eventPrefix and prefixEvent from component config which can be replaced by bubbleEvents.
Add ownerCt to reflect component's owner container.
Item config now can be a function.
Fix the destroy()method.
2012-03-17: Release version 2.1with the following updates:

Append record and store to event arguments
Update internal code
2012-04-23: Release version 2.2 with the following updates:

Update internal code
2012-05-05: Release version 2.3 with the following updates:

Update internal code
Source code


/**
* @class Its.grid.column.Component
* @extends Ext.grid.column.Column
* @xtype itscomponentcolumn
* @version 2.3
* @author Nguyen Truong Sinh (vietits@yahoo.com)
*
* A column definition class which renders a component, or a series of components in a grid cell.
*
* @example
* var store = Ext.create('Ext.data.Store', {
* fields:['taskname', 'status', 'assignTo', 'dep'],
* data:[
* {taskname:"Task 1", status:1, assignTo:"Scott", dep:"Manangement"},
* {taskname:"Task 2", status:2, assignTo:"John", dep:"Sales"},
* {taskname:"Task 3", status:2, assignTo:"Smith", dep:"Accounting"},
* {taskname:"Task 4", status:3, assignTo:"Smith", dep:"Accounting"}
* ]
* });
*
* Ext.create('Ext.grid.Panel', {
* title: 'Component Column Demo',
* name : 'task',
* store: store,
* columns: [{
* .......
* },{ // a column with a combobox
* xtype: 'itscomponentcolumn',
* text : 'Status',
* width: 160,
* name : 'status',
* dataIndex: 'status',
* items: {
* prepare: function(config, value) {
* return {
* xtype: 'combobox',
* store: [[1,'In Queue'], [2,'Handling'], [3,'Complete']],
* value: value
* };
* }
* }
* },{ // a column with two buttons to modify/delete task
* xtype: 'itscomponentcolumn',
* align: 'center',
* width: 50,
* name : 'action',
* defaults: { // default configs applied for all items
* xtype: 'button',
* width: 'auto'
* },
* items: [{
* iconCls: 'icon-modify',
* action : 'modify',
* tooltip: 'Modify this task'
* },{
* iconCls: 'icon-delete',
* action : 'delete',
* tooltip: 'Delete this task'
* }]
* }],
* width: 400,
* renderTo: Ext.getBody()
* });
*
* # Default settings
*
* - hideable: false
* - groupable: false
* - defaultType: 'component'
*
* # Child component events
*
* The following arguments will be added to the end of argument list of each event:
*
* - record The record providing the data.
* - rowIndex The row index.
* - colIndex The column index.
* - store The store which provides model data
* - view The grid view object.
* - comp The component itself.
*
* @update 2012-01-14 22:37:21
* Release version 1.0
*
* @update 2012-01-24 08:37:09
* Release version 2.0 with the following updates:
* - Remove relayEvents, eventPrefix and prefixEvent from component config which can be replaced by bubbleEvents and bubblePrefix.
* - Add ownerCt to reflect component's owner container.
* - Add the ability that is an item config can be a function.
* - Fix the destroy() method.
*
* @update 2012-03-17 21:23:34
* Release version 2.1 with the following updates:
* - Append record and store to event arguments
* - Update internal code
* @update 2012-04-23 19:48:46
* Release version 2.2 with the following updates:
* - Update internal code
* @update 2012-05-05 09:58:07
* Release version 2.3 with the following updates:
* - Update internal code
*/


Ext.define('Its.grid.column.Component', {
extend: 'Ext.grid.column.Column',
alias : 'widget.itscomponentcolumn',


/**
* @cfg {String/Function/Object/String[]/Function[]/Object[]} items
* Child component configs. Items can be:
* - an xtype (string) or array of xtype (string[])
* - a function which returns item config object or an array of functions.
* Function will be called with following arguments:
* + value The value of the column's configured field (if any).
* + record The record providing the data.
* + rowIndex The row index.
* + colIndex The column index.
* + store The store which is providing the data Model.
* + view The current view.
* - an object which represents item conig or an array of config objects
* - mix of above types.
*
* Besides the normal component configs, each item may contain:
*
* @cfg {Function} items.prepare A function which returns the component config.
* @cfg {Object} items.prepare.config The current config.
* @cfg {Object} items.prepare.value The value of the column's configured field (if any).
* @cfg {Ext.data.Model} items.prepare.record The record providing the data.
* @cfg {Number} items.prepare.rowIndex The row index.
* @cfg {Number} items.prepare.colIndex The column index.
* @cfg {Ext.data.Store} items.prepare.store The store which is providing the data Model.
* @cfg {Ext.grid.View} items.prepare.view The current view.
*
* @cfg {Object} items.scope The scope (`this` reference) in which the `prepare` function
* is executed.
*/

constructor: function(config) {
var me = this;
var cfg = Ext.apply({
hideable: false,
groupable: false,
defaultType: 'component'
}, config);
var lst = cfg.items;
var def = cfg.defaults;


delete cfg.items;
delete cfg.columns;
delete cfg.defaults;

me.callParent([cfg]);


me.defaults = def;
me.queue = {};
me.comps = Ext.create('Ext.util.MixedCollection', false, me.getComponentId);
me.itemsConfig = [];
lst = Ext.isArray(lst) ? lst : [lst];
Ext.Array.each(lst, function(itm) {
if(Ext.isString(itm)) {
itm = {xtype: itm};
}
if(Ext.isObject(itm) || Ext.isFunction(itm)) {
me.itemsConfig.push(itm);
}
});


me.renderer = function(value, meta, record, rowIdx, colIdx, store, view) {
var ret = '';
var src = me.renderer.caller;
if (src.$owner && src.$owner.xtype == 'headercontainer') {
var iid = me.getIdPrefix(record);
me.queue[iid] = {
view : view,
store : store,
value : value,
record: record,
rowIdx: rowIdx,
colIdx: colIdx
};
ret = (Ext.isFunction(cfg.renderer) ? cfg.renderer.apply(cfg.scope || me, arguments) || '' : '')
+ '<div id="' + iid + '">&#160;</div>';
}
return ret;
};
},
onRender: function() {
var me = this;
var pnl = me.up('tablepanel');
var view= pnl.getView();


me.mon(view, 'refresh' , me.injectItems, me);
me.mon(view, 'itemadd' , me.injectItems, me);
me.mon(view, 'itemupdate', me.injectItems, me);
me.callParent(arguments);
},
getIdPrefix : function(record) {
return Ext.String.format('{0}-{1}', this.getId(), record.internalId);
},
injectItems: function() {
var me = this;
var queue = me.queue;
var items = me.itemsConfig;
var cfLen = items.length;


me.queue = {};
for(var iid in queue) {
var itm = queue[iid];
var elm = Ext.get(iid);
if(elm) {
for(var idx = 0; idx < cfLen; idx++) {
var cfg = Ext.clone(items[idx]) || {};


if(Ext.isFunction(cfg)) {
cfg = cfg(itm.value, itm.record, itm.rowIdx, itm.colIdx, itm.store, itm.view);
}
if(Ext.isFunction(cfg.prepare)) {
cfg = cfg.prepare.call(cfg.scope || cfg, cfg, itm.value, itm.record, itm.rowIdx, itm.colIdx, itm.store, itm.view);
}
delete cfg.prepare;
cfg = me.applyDefaults(cfg);


cfg.itemId = iid + '-' + idx;


me.removeItem(cfg.itemId);

var cmp = me.lookupComponent(cfg);
if(cmp && cmp.isComponent) {
cmp.fireEvent = Ext.bind(cmp.fireEvent, cmp, [itm.record, itm.rowIdx, itm.colIdx, itm.store, itm.view, cmp], true);
cmp.render(elm.parent(), elm);
if (Ext.isIE6) {
elm.parent().repaint();
}
cmp.ownerCt = me;
me.comps.add(cmp);
}
}
elm.remove();
}
}
},
onItemRemove: function(record) {
var me = this;
var iid = me.getIdPrefix(record);
var idx = 0;


while(me.removeItem(iid + '-' + idx)) {
idx++;
}
},
removeItem: function(cmp) {
var me = this;
var ret = false;


if(Ext.isString(cmp)) {
cmp = me.comps.getByKey(cmp);
}
if(cmp) {
cmp.ownerCt = null;
me.comps.remove(cmp);
cmp.destroy();
ret = true;
}
return ret;
},
$callParent: function(args) {
var me = this;
var ret = null;
var method = me.$callParent.caller,
parentClass, methodName;


if (!method.$owner) {
method = method.caller;
}
parentClass = method.$owner.superclass;
methodName = method.$name;


if(me.items === me.comps) {
ret = parentClass[methodName].apply(me, args || []);
} else {
var items = me.items;
me.items = me.comps;
ret = parentClass[methodName].apply(me, args || []);
me.items = items;
}
return ret;
},
beforeDestroy: function() {
var me = this;


me.$callParent(arguments);
Ext.destroyMembers(me, 'comps', 'queue', 'renderer');
},
doRemove: function(cmp) {
this.$callParent(arguments)
},
removeAll: function() {
return this.$callParent(arguments);
},
getComponent: function() {
return this.$callParent(arguments);
},
getRefItems: function() {
return this.$callParent(arguments);
},
cascade: false
});

Example


Ext.require([
'Ext.picker.*',
'Ext.form.*',
'Ext.grid.*',
'Ext.data.*',
'Ext.panel.*',
'Ext.chart.*',
'Ext.chart.axis.Gauge',
'Ext.chart.series.*',
'Its.grid.column.Component'
]);

Ext.onReady(function() {
var store = Ext.create('Ext.data.Store', {
fields:['taskname', 'status', 'done', 'assignTo', 'dep', 'date', {name:'qty', type: 'int'}],
data:[
{taskname:"Task 1", status:1, done: 10, assignTo:"Scott", dep:"Manangement", date: '2012-01-01', qty:20},
{taskname:"Task 2", status:2, done: 30, assignTo:"John", dep:"Sales", date: '2012-01-12', qty:35},
{taskname:"Task 3", status:2, done: 50, assignTo:"Smith", dep:"Accounting", date: '2012-01-21', qty:12},
{taskname:"Task 4", status:3, done: 70, assignTo:"Smith", dep:"Accounting", date: '2012-01-05', qty:51}
]
});

Ext.create('Ext.grid.Panel', {
title: 'Component Column Demo',
name : 'task',
store: store,
width: 900,
height: 950,
renderTo: Ext.getBody(),
columns: [{
text: 'Task name',
flex: 1,
dataIndex: 'taskname'
},{ // chart column
xtype: 'itscomponentcolumn',
text : 'Chart',
width: 200,
dataIndex: 'done',
items: function(value) {
return {
xtype: 'chart',
width: 200,
height: 150,
style: 'background:#fff',
animate: {
easing: 'elasticIn',
duration: 1000
},
store: Ext.create('Ext.data.Store', {
fields: ['gauge'],
data : [{gauge: value}]
}),
insetPadding: 25,
flex: 1,
axes: [{
type: 'gauge',
position: 'gauge',
minimum: 0,
maximum: 100,
steps: 10,
margin: -10
}],
series: [{
type: 'gauge',
value: value,
field: 'gauge',
donut: false,
colorSet: ['#F49D10', '#ddd']
}]
}
}
},{ // column with a combobox
xtype: 'itscomponentcolumn',
text : 'Combobox',
name : 'status',
width: 160,
dataIndex: 'status',
items: function(value) {
return {
xtype: 'combobox',
store: [[1,'In Queue'], [2,'Handling'], [3,'Complete']],
value: value,
width: 130
};
}
},{ // column with a spinner
xtype: 'itscomponentcolumn',
text : 'Spinner',
width: 50,
dataIndex: 'qty',
items: function(value) {
return {
xtype: 'spinnerfield',
value: value,
width: 25
};
}
},{ // column with date picker
xtype: 'itscomponentcolumn',
text : 'Date picker',
dataIndex: 'date',
width: 200,
items: function(value) {
return {
xtype: 'datepicker',
width: 190,
value: new Date(value)
};
}
},{ // column with checkboxes
xtype: 'itscomponentcolumn',
text : 'Checkbox',
defaultType: 'checkboxfield',
items: [{
boxLabel : 'Anchovies',
name : 'topping',
inputValue: '1',
}, {
boxLabel : 'Artichoke Hearts',
name : 'topping',
inputValue: '2',
checked : true,
}, {
boxLabel : 'Bacon',
name : 'topping',
inputValue: '3',
}]
},{ // column with two buttons
xtype: 'itscomponentcolumn',
text : 'Buttons',
align: 'center',
width: 60,
name : 'action',
sortable: false,
defaults: { // default configs applied for all items
xtype: 'button',
width: 'auto'
},
items: [{
iconCls: 'icon-modify',
action : 'modify',
tooltip: 'Modify this task'
},{
iconCls: 'icon-delete',
action : 'delete',
tooltip: 'Delete this task'
}]
}]
});
});

mitchellsimoens
15 Jan 2012, 2:51 PM
Does it work for 4.1.0?

vietits
15 Jan 2012, 6:32 PM
Hi Mitchell,

Because of some basic differences between Ext 4.0.7 and Ext 4.1.0-beta-1 so I am sure this component will not work on 4.1.0 if we won't adjust some things.

This component uses method `relayEvents` to relay events from child components. However, the implementations of `relayEvents` in these versions of Ext are different:

with 4.0.7: event names must be prefixed with eventPrefix before calling method `relayEvents`.
with 4.1.0: event names will be prefixed with eventPrefix by method `relayEvents`.
This feature will be affected if you want to relay events from child components and capture them at the column component. If it is the case, you must adjust the configs (in this case these are prefixEvent and relayEvents) of child components. Below is one such example:

With 4.0.7

{
xtype: 'itscomponentcolumn',
items: [{
xtype: 'button',
relayEvents: ['click'],
eventPrefix: 'button',
prefixEvent: true // the component will prefix each event name with eventPrefix before calling relayEvents
}]
...
}

With 4.1.0-beta-1

{
xtype: 'itscomponentcolumn',
items: [{
xtype: 'button',
relayEvents: ['click'],
eventPrefix: 'button',
prefixEvent: false // the component won't prefix event names with eventPrefix
}]
...
}

skirtle
16 Jan 2012, 4:15 PM
This is very interesting. It's attempting to solve the same problem as my own Component Column but the approach is quite different:

http://www.sencha.com/forum/showthread.php?148064

I need to study your code in more detail to understand better how it works. I see a few things that look very similar to my own code but other sections, like the event relaying, that are totally different.

vietits
16 Jan 2012, 5:31 PM
Hi Skirtle,

I'm happy that you are interested in my component. Hope that it is easy for you to understand how it works. To help you easier in understanding my component, here are some briefs of its features:

It can be appears one or more times in a grid.
It can contain one or more components in one column. Components can be the same xtype or not.
It appends cell information (rowIndex, colIndex) and others (view, itself) to the end of each event argument of each component.
It attachs cell information (rowIndex, colIndex, view) to each component through the cellInfo property so you can refer to these in your code.
It can relay component events by setting respective configs (relayEvents, eventPrefix, prefixEvent)
Though I developed this component for 4.0.7, but I have tested it with 4.1.0-beta-1 and it works fine, but with one thing to remember (as I mentioned in the ealier reply) is that you should set prefixEvent to false.

I hope to get useful responses from you to improve this component more useful.

vietits
27 Jan 2012, 11:44 PM
Release version 2.0 (updated on the first post of this thread) with the following updates:

Remove relayEvents, eventPrefix and prefixEvent from component config which can be replaced by bubbleEvents.
Add ownerCt to reflect component's owner container.
Item config now can be a function.
Fix the destroy() method.

NCN
23 Apr 2012, 1:28 AM
hi vietits (http://www.sencha.com/forum/member.php?362966-vietits)

can you please upload your updated code which will work in our local sys. as well.

I want the graph in grid cell for the sencha touch 2.

Thanks in advance !!!

vietits
23 Apr 2012, 5:08 AM
I have updated Its.grid.column.Component to version 2.2 on the first post of this thread. Please see more details there.

ramana_l_v
27 Apr 2012, 8:16 AM
Hi vietits,
This is very interesting, but I am having a very strange problem I am using 2.2 version of your code. If I add a textfield or textarea I am unable to enter space in those fields. Below is my code where I am just adding a textfield component, I am not sure what I am doing wrong.



Ext.define('iLab.view.ui.GenericDetailsGrid', {
extend: 'Ext.grid.Panel',


height: 650,
hideHeaders: true,
showTemplate: false,
backButtonTitle: 'iLab',
disableSelection : true,
stripeRows: false,

initComponent: function() {
var me = this;


Ext.applyIf(me, {
columns: [
.....
{
xtype: 'itscomponentcolumn',
flex: 1,
dataIndex: 'type',
items: function(value, record, rowIndex, colIndex, store) {
return {
xtype: 'textfield',
itemId: 'buzzReplyMessagee'
};
}
}
],
viewConfig: {
stripeRows: false
}


});


me.callParent(arguments);
}

});

Thanks in advance...

skirtle
27 Apr 2012, 8:59 AM
Some key presses are caught by the grid for navigation. Try adding this listener to your textfield:


listeners: {
inputEl: {
keydown: function(ev) {
ev.stopPropagation();
}
}
}

vietits
27 Apr 2012, 3:23 PM
@Skirtle,

Thanks for your information .

oguz.
2 May 2012, 2:58 AM
Hi, i try to use this plugin in my application. I need to disable the component according to the value of another column value. For example i have two columns. one is checkbox, and the other one is a combobox. if the checbox is checked combo should be active and if checkbox is not checked combo should be disabled.
I try to use cellediting plugin but it isnot running compatible with this component.
How can i disable the component according to the value of another column value?

Best Regards.
Oguz

vietits
2 May 2012, 6:30 AM
Hi, i try to use this plugin in my application. I need to disable the component according to the value of another column value. For example i have two columns. one is checkbox, and the other one is a combobox. if the checbox is checked combo should be active and if checkbox is not checked combo should be disabled.
I try to use cellediting plugin but it isnot running compatible with this component.
How can i disable the component according to the value of another column value?

Best Regards.
Oguz
Below is an example that use Its.grid.column.Component that works with what you mentioned. The first field is editable by using CellEditing.


Ext.require([
'Ext.*',
'Its.grid.column.Component'
]);
Ext.onReady(function(){
var cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
});
var store = Ext.create('Ext.data.Store', {
fields:['name', 'selected', 'checked'],
data :[
{name: 'A', selected:1, checked: true},
{name: 'B', selected:2, checked: false},
{name: 'C', selected:2, checked: true},
{name: 'D', selected:3, checked: true}
]
});

Ext.create('Ext.grid.Panel', {
title: 'Component Column Demo',
store: store,
width: 300,
height: 250,
renderTo: Ext.getBody(),
plugins: [cellEditing],
columns: [{
header: 'Name',
dataIndex: 'name',
flex: 1,
editor: {
allowBlank: false
}
},{
xtype: 'itscomponentcolumn',
text : 'Combobox',
width: 160,
dataIndex: 'selected',
items: function(value, record, rowIdx) {
return {
xtype: 'combobox',
index: rowIdx,
store: [[1,'In Queue'], [2,'Handling'], [3,'Complete']],
value: value,
disabled: !record.get('checked'),
width: 130
};
}
},{ // column with checkboxes
xtype: 'itscomponentcolumn',
text : 'Checkbox',
width: 90,
dataIndex: 'checked',
items: function(value){
return {
xtype : 'checkboxfield',
name : 'topping',
checked : value,
listeners: {
change: function(field, newValue, oldValue, record, rowIdx){
var grid = this.up('grid');
var combobox = grid.down('combobox[index=' + rowIdx + ']');
combobox.setDisabled(!field.checked);
}
}
};
}
}]
});
});

Note: Its.grid.column.Component is a grid column that allows to display component(s) in grid cell. It does not do the role of CellEditing or RowEditing.

kstewart
15 May 2012, 8:55 AM
I have what may turn out to be a simple question, but it has been plaguing me for days now. (View the attached image for reference.) I want to hide the control in position (0,0) always. Should the user insert a new row above the zeroth row (thus making the new row the zeroth row and the old zeroth row now the 1st row.) At this point I now also need to show the control for the new 1st row (which was bumped down by the insertion of the new zeroth row.) Make any sense? I basically need to be able to arbitrarily show/hide components in cells. Any help would be greatly appreciated.

Kevin

crocop21
21 Jun 2012, 1:05 PM
I have a question
Ext.require([
'Its.grid.column.Component'
]);

I dont understand how i need to save the file Component.js because i have this error

uncaught exception: Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. Missing required class: Its.grid.column.Component

i have to save in the folder: Its\grid\column ?

another_i
22 Jun 2012, 12:33 AM
I have a question
Ext.require([
'Its.grid.column.Component'
]);

I dont understand how i need to save the file Component.js because i have this error

uncaught exception: Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. Missing required class: Its.grid.column.Component

i have to save in the folder: Its\grid\column ?

I don't know why this ux named as Its.grid.column.Component. I rename it as Ext.ux.grid.column.Component and put it in my /ext4_ux folder: ext4_ux/grid/column/Component.js. Loader is:



Ext.Loader.setConfig({
enabled: true,
paths: {
'App': '/app',
'Ext': '/ext4/src',
'Ext.ux': '/ext4_ux'
}
});

Ext.require(['Ext.ux.grid.column.Component']);


So you can use this code:


Ext.Loader.setConfig({
enabled: true,
paths: {
'App': '/app',
'Ext': '/ext4/src',
'Ext.ux': '/ext4/src/ux', // by default UX are here
'Its': '/ext4/src/ux'
// if the Component.js path is /ext4/src/ux/grid/column/Component.js
}
});

Ext.require(['Its.grid.column.Component']);



And thanks to author for the great UX!

crocop21
22 Jun 2012, 7:45 AM
I don't know why this ux named as Its.grid.column.Component. I rename it as Ext.ux.grid.column.Component and put it in my /ext4_ux folder: ext4_ux/grid/column/Component.js. Loader is:



Ext.Loader.setConfig({
enabled: true,
paths: {
'App': '/app',
'Ext': '/ext4/src',
'Ext.ux': '/ext4_ux'
}
});

Ext.require(['Ext.ux.grid.column.Component']);


So you can use this code:


Ext.Loader.setConfig({
enabled: true,
paths: {
'App': '/app',
'Ext': '/ext4/src',
'Ext.ux': '/ext4/src/ux', // by default UX are here
'Its': '/ext4/src/ux'
// if the Component.js path is /ext4/src/ux/grid/column/Component.js
}
});

Ext.require(['Its.grid.column.Component']);



And thanks to author for the great UX!
Thanks for the answer i was trying to implement the example i think i did all good, but is show in me the explorer in blank and any error in the firebug and i tried too in chrome but is the same
I am using extjs4.1, i didnt had the folder ux inside of src, and i created the folder column because didnt had inside of the folder grid. here is my code:


<!DOCTYPE html>

<!-- Auto Generated with Sencha Architect -->
<!-- Modifications to this file will be overwritten. -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>edit</title>
<link rel="stylesheet" type="text/css" href="ext4/resources/css/ext-all.css"/>
<script type="text/javascript" src="ext4/ext-all-debug.js"></script>

</head>
<body>
<script type="text/javascript">
Ext.Loader.setConfig({
disableCaching: false,
enabled: true,
paths: {
'App': '/app',
'Ext': 'ext4/',
'Ext.ux': 'ext4/examples/ux/'
}
});

Ext.require(['Ext.ux.grid.column.Component']),

Ext.onReady(function() {
var store = Ext.create('Ext.data.Store', {
fields:['taskname', 'status', 'done', 'assignTo', 'dep', 'date', {name:'qty', type: 'int'}],
data:[
{taskname:"Task 1", status:1, done: 10, assignTo:"Scott", dep:"Manangement", date: '2012-01-01', qty:20},
{taskname:"Task 2", status:2, done: 30, assignTo:"John", dep:"Sales", date: '2012-01-12', qty:35},
{taskname:"Task 3", status:2, done: 50, assignTo:"Smith", dep:"Accounting", date: '2012-01-21', qty:12},
{taskname:"Task 4", status:3, done: 70, assignTo:"Smith", dep:"Accounting", date: '2012-01-05', qty:51}
]
});
store.load();

var panel = Ext.create('Ext.grid.Panel', {
title: 'Component Column Demo',
name : 'task',
store: store,
width: 900,
height: 950,
autoShow: true,
//renderTo: Ext.getBody(),
columns: [{
text: 'Task name',
flex: 1,
dataIndex: 'taskname'
},{ // chart column
xtype: 'itscomponentcolumn',
text : 'Chart',
width: 200,
dataIndex: 'done',
items: function(value) {
return {
xtype: 'chart',
width: 200,
height: 150,
style: 'background:#fff',
animate: {
easing: 'elasticIn',
duration: 1000
},
store: Ext.create('Ext.data.Store', {
autoLoad: true,
fields: ['gauge'],
data : [{gauge: value}],

}),

insetPadding: 25,
flex: 1,
axes: [{
type: 'gauge',
position: 'gauge',
minimum: 0,
maximum: 100,
steps: 10,
margin: -10
}],
series: [{
type: 'gauge',
value: value,
field: 'gauge',
donut: false,
colorSet: ['#F49D10', '#ddd']
}]
}
}
},{ // column with a combobox
xtype: 'itscomponentcolumn',
text : 'Combobox',
name : 'status',
width: 160,
dataIndex: 'status',
items: function(value) {
return {
xtype: 'combobox',
store: [[1,'In Queue'], [2,'Handling'], [3,'Complete']],
value: value,
width: 130
};
}
},{ // column with a spinner
xtype: 'itscomponentcolumn',
text : 'Spinner',
width: 50,
dataIndex: 'qty',
items: function(value) {
return {
xtype: 'spinnerfield',
value: value,
width: 25
};
}
},{ // column with date picker
xtype: 'itscomponentcolumn',
text : 'Date picker',
dataIndex: 'date',
width: 200,
items: function(value) {
return {
xtype: 'datepicker',
width: 190,
value: new Date(value)
};
}
},{ // column with checkboxes
xtype: 'itscomponentcolumn',
text : 'Checkbox',
defaultType: 'checkboxfield',
items: [{
boxLabel : 'Anchovies',
name : 'topping',
inputValue: '1',
}, {
boxLabel : 'Artichoke Hearts',
name : 'topping',
inputValue: '2',
checked : true,
}, {
boxLabel : 'Bacon',
name : 'topping',
inputValue: '3',
}]
},{ // column with two buttons
xtype: 'itscomponentcolumn',
text : 'Buttons',
align: 'center',
width: 60,
name : 'action',
sortable: false,
defaults: { // default configs applied for all items
xtype: 'button',
width: 'auto'
},
items: [{
iconCls: 'icon-modify',
action : 'modify',
tooltip: 'Modify this task'
},{
iconCls: 'icon-delete',
action : 'delete',
tooltip: 'Delete this task'
}]
}]
});

panel.render(document.body);
});
</script>
</body>
</html>

And in the extension i modified only this


Ext.define('Ext.grid.column.Component', {
extend: 'Ext.grid.column.Column',
alias : 'widget.itscomponentcolumn',

skirtle
22 Jun 2012, 8:20 AM
I don't know why this ux named as Its.grid.column.Component. I rename it as Ext.ux.grid.column.Component

Namespaces should reflect the organisation or individual who released the code. Sencha use the Ext namespace, vietits has chosen to use the Its namespace. It's an entirely appropriate way to namespace the class and I would advise against renaming it to either the Ext or Ext.ux namespace.

Historically the Ext.ux namespace was used for user extensions but this was a mistake. It totally defeats the uniqueness requirements for namespaces and in the eyes of many users it conveys the misleading impression that code was written by Sencha. Obviously there is little that can be done to stop users writing extensions in the Ext.ux namespace but I would strongly advise against it. That namespace should only be used by Sencha for their demo components.

It certainly shouldn't be necessary to rename the class to get the dynamic loader to work. You can put the file wherever you want but it must be called Component.js. You then just need to configure the paths for the namespace. If you choose to put the file in a folder structure of grid/column/Component.js then you'll only need to configure the loader with the path for the Its namespace. If you choose to put it in a totally random folder then you'd need to configure the loader with the path for the whole Its.grid.column namespace.

crocop21
22 Jun 2012, 8:49 AM
Well i think i did all good my folder structure, maybe is not working with extjs version 4.1??

vietits
22 Jun 2012, 3:26 PM
@crocop21,

Its.grid.column.Component works with Ext 4.1. To use this component (and other user extensions), you should config Ext.Loader to inform Its namespace. Skirtle's suggestion is good to follow. Below is an example:
Suppose you save Component.js in the folder /Its/grid/column/Component.js, then you should config Ext.Loader as below:


Ext.Loader.setConfig({
enabled: true, // enable dynamic loading
paths: {
'Its': '/Its',
... // other namespace
}
});

Ext.require(['Its.grid.column.Component']);

crocop21
25 Jun 2012, 7:18 AM
Hey thanks for the answer, its working now, i am trying to implement with Ext.grid.plugin.CellEditing
but its show in blank, is posible to do this?




xtype: 'itscomponentcolumn',
autoRender: true,
autoShow: false,
width: 150,
dataIndex: 'country',
editor: {

items: function(value) {
return {
xtype: 'combobox',
store: [[1,'In Queue'], [2,'Handling'], [3,'Complete']],
value: value,
width: 130
};
}

},

vietits
26 Jun 2012, 1:22 AM
The items config should be defined outside editor config. Something likes this:


xtype: 'itscomponentcolumn',
autoRender: true,
autoShow: false,
width: 150,
dataIndex: 'country',
items: function(value) {
return {
xtype: 'combobox',
store: [[1,'In Queue'], [2,'Handling'], [3,'Complete']],
value: value,
width: 130
};
},
editor: {
// define editor config for cellediting
},

One thing to mention here is that this component is for displaying components in grid cell, it is not replacement for cellediting or rowediting plugins.

crocop21
26 Jun 2012, 5:34 AM
The items config should be defined outside editor config. Something likes this:


xtype: 'itscomponentcolumn',
autoRender: true,
autoShow: false,
width: 150,
dataIndex: 'country',
items: function(value) {
return {
xtype: 'combobox',
store: [[1,'In Queue'], [2,'Handling'], [3,'Complete']],
value: value,
width: 130
};
},
editor: {
// define editor config for cellediting
},

One thing to mention here is that this component is for displaying components in grid cell, it is not replacement for cellediting or rowediting plugins.

And how can edit the combobox, i was trying something like this but when i edit is show me both combos from the component, and editor..thanks...
36539


xtype: 'itscomponentcolumn',
autoRender: false,
autoShow: false,
width: 150,
dataIndex: 'country',

items: function(value) {
return {
xtype: 'combobox',
store: [[1,'In Queue'], [2,'Handling'], [3,'Complete']],
value: value,
width: 130
};
},
editor: {
xtype: 'combobox',
store: [['In Queue','In Queue'], ['In Queue','Handling'], ['In Queue','Complete']]
},
fixed: false,
text: 'Country'
},

vietits
26 Jun 2012, 5:13 PM
Before showing the editor for grid cell editing, the cellediting plugin will try to hide the content of the grid cell. However, this is applied to text content only. In your case, the grid cell content is not text but component, so it won't be hidden. That's the reason why you see both comboboxes when you switch to editing mode.

skirtle
26 Jun 2012, 5:27 PM
I don't understand why you would want to use this extension in combination with cell editing. Why would you want to show yet another combobox in the cell rather than just use the one you already have?

crocop21
27 Jun 2012, 4:38 AM
I don't understand why you would want to use this extension in combination with cell editing. Why would you want to show yet another combobox in the cell rather than just use the one you already have?

So its imposible to do it?, i want to show the component in the cell editing because i want the user knows is a combo when try to edit.. Thanks alot for answer!, mm this extension can use for edit? i mean without cell editing?

ganlhi
18 Jul 2012, 1:29 AM
Hello !

First, thanks for this extension, which solve a problem I had since monday.

My only issue is that if I use a Ext.Component or any form field as a cell content, it works perfectly; but if I use an Ext.Container or any subclass (like a panel), the grid doesn't scroll anymore...

Anyone knows how to handle that (if it is possible) ?
Thanks.

EDIT :
After some test, it appears that the scrolling appears when the panel has a height greater than a "normal" row height.
It seems that the total height occupied by the rows is not properly calculated after the panel is displayed.
This problem occurs also when using Ext.Component, if this one is too high.

EDIT 2 :
No I'm wrong: it works with components, not with containers.

EDIT 3 : After some more tests, the problem appears only if my panel contains grid panels.

another_i
18 Jul 2012, 9:32 PM
Namespaces should reflect the organisation or individual who released the code. Sencha use the Ext namespace, vietits has chosen to use the Its namespace. It's an entirely appropriate way to namespace the class and I would advise against renaming it to either the Ext or Ext.ux namespace.

Historically the Ext.ux namespace was used for user extensions but this was a mistake. It totally defeats the uniqueness requirements for namespaces and in the eyes of many users it conveys the misleading impression that code was written by Sencha. Obviously there is little that can be done to stop users writing extensions in the Ext.ux namespace but I would strongly advise against it. That namespace should only be used by Sencha for their demo components.

It certainly shouldn't be necessary to rename the class to get the dynamic loader to work. You can put the file wherever you want but it must be called Component.js. You then just need to configure the paths for the namespace. If you choose to put the file in a folder structure of grid/column/Component.js then you'll only need to configure the loader with the path for the Its namespace. If you choose to put it in a totally random folder then you'd need to configure the loader with the path for the whole Its.grid.column namespace.

Thanks for the detailed answer.

dbrin
12 Aug 2012, 3:00 PM
I am having a bit of a problem passing in scope into the handler of a menu item. Regular columns have scope property that can be set and then renderer handler runs in that scope. Any help on how to achieve a similar scoped handler for the items function?

Lukappa
9 Feb 2013, 4:46 AM
Hello,
after updating my ExtJs from 4.1.3 to 4.2.0 beta 2 the componentcolumn stopped to work (without errors/warnings).

I have just found the reason:
Inside the constructor method there is this code:


me.renderer = function(value, meta, record, rowIdx, colIdx, store, view) {
var ret = '';
var src = me.renderer.caller;
if (src.$owner && src.$owner.xtype == 'headercontainer') {
var iid = me.getIdPrefix(record);
me.queue[iid] = {
view : view,
store : store,
value : value,
record: record,
rowIdx: rowIdx,
colIdx: colIdx
};
ret = (Ext.isFunction(cfg.renderer) ? cfg.renderer.apply(cfg.scope || me, arguments) || '' : '')
+ '<div id="' + iid + '"> </div>';
}
return ret;
};


Checking the src.$owner.xtype, I saw now it's "tableview" and not "headercontainer" as expected by this component.
I fixed this problem changing

if (src.$owner && src.$owner.xtype == 'headercontainer') { ...
with

if (src.$owner) { ...

My first tests are good... If I will find any error I will post here.

deving
17 Apr 2013, 10:53 AM
I really like this component. I am able to get the combobox working in a grid column. However, what I need is to have the options in the combobox be different for each row. Is this possible? I currently have json data for the rows with nested data for the options. Can this be done and how? Thank you!

Edit: I have now got this working...so my new issue is handling a select event in the combo box...seems to be firing the grid select event instead?

smartbinary
8 May 2013, 12:21 PM
trying to work with 4.2.0 and running into problems - even after applying the patch:



...
after updating my ExtJs from 4.1.3 to 4.2.0 beta 2 the componentcolumn stopped to work (without errors/warnings).
...
I fixed this problem changing

if (src.$owner && src.$owner.xtype == 'headercontainer') { ...
with

if (src.$owner) { ...
....


anyone got this component upgraded for use in 4.2.0? or...is there even a better solution than this component built into 4.2.0?

smartbinary
9 May 2013, 11:45 AM
trying to work with 4.2.0 and running into problems - even after applying the patch:


here's the fix - resolves issue w/4.2.0 - add



cmp.setupProtoEl();


just before the line



cmp.render(elm.parent(), elm);

sai571
22 May 2013, 7:34 AM
This is not working out of the box w/ Ext JS 4.2 version, please give the source code which works without patches/hacks.

fshort
6 Jun 2013, 3:41 AM
Using v2.3 with extjs 4.2.1. When I refresh the grid store, looks like the children of the itscomponent column are not being destroyed. If I keep refreshing the grid, I see the children objects continue to accumulate in the DOM. Has anyone experienced this before? Code looks like this:


{
xtype: 'itscomponentcolumn',
text: 'Trend',
flex: 2,
align: 'center',
name : 'hits',
menuDisabled: true,
dataIndex: 'hits',
items: function(value, rec, idx, y, st, view) {
var storeId = rec.get("collectionName") + ":" + rec.get("metaproj") + ":" + rec.get("proj") + ":" + rec.get("entity");
return {
xtype: 'chart',
id: storeId,
border: false,
animate: false,
margin: 5,
height: 40,
width: 300,
label: {
position: 'right',
display: 'text',
labelText: st.getAt(idx).get("totalHits")
},
store: Ext.create('Ext.data.JsonStore', {
storeId: storeId,
model: 'mymodel',
data: value
}),
shadow: false,
axes: [{
type: 'Numeric',
dashSize: 1,
position: 'left',
fields: ['ct']
}, {
type: 'Category',
dashSize: 1,
position: 'bottom',
fields: ['hm']
}],
series: [{
type: 'line',
showMarkers: false,
axis: 'left',
xField: 'hm',
yField: 'ct'
}]
};
}
}]

Scorpie
11 Jun 2013, 6:50 AM
This is not working out of the box w/ Ext JS 4.2 version, please give the source code which works without patches/hacks.

You could do it yourself. =D>

ananthk
13 Jul 2013, 11:02 AM
Can someone please help me quckly to enable me display the nested JSON chart data in this code. When the store loads it does have the nested JSON data and I have provide the firebug snapshot. I am not sure what am I doing wrong to enable the chart work. I really appreciate your help quickly. I can't access the data as a single field in the grid as well


Ext.require([
'Ext.picker.*',
'Ext.form.*',
'Ext.grid.*',
'Ext.data.*',
'Ext.panel.*',
'Ext.chart.*',
'Its.grid.column.Component'
]);




Ext.define('Org.model.MetricsModel', {
extend: 'Ext.data.Model',
config: {
fields: [
{
name: 'orgname',
type: 'string'
},
{
name: 'successcount',
type:'int'
},
{
name: 'errorcode1',
type:'int'
},
{
name: 'errorcode2',
type:'int'
},
{
name: 'errorcode3',
type:'int'
},
{ name: 'time', type: 'string', mapping: 'chartdata.timeinterval' },
{ name: 'error', type: 'string', mapping: 'chartdata.errorcount' },
{ name: 'success', type: 'string', mapping: 'chartdata.successcount' }


],
hasMany: [
{
model: 'Org.model.ChartModel',
autoLoad: true,
name: 'chartdata'
}

]
}
});
Ext.define('Org.model.ChartModel', {
extend : 'Ext.data.Model',
config : {
idProperty : 'timeinterval',
fields : [
'timeinterval',
'errorcount',
'successcount'
],
belongsTo: 'Org.model.MetricsModel'
}
});


Ext.onReady(function() {


var store = new Ext.data.Store({
autoLoad : true,
model : 'Org.model.MetricsModel',
proxy : {
type : 'ajax',
url : 'data/json.json',
reader : 'json'
},
listeners : {
load : function(store) {
var rec = store.getAt(5),
chartdata = rec.chartdata();


console.log('There are ' + chartdata.getCount() + ' chardata');
//console.log('There is ' + jobDates.getCount() + ' job date');
}
},

data: [
{
"orgname": "MYORG1",
"successcount": 2,
"errorcode1": 2,
"errorcode2": 2,
"errorcode3": 2,

"chartdata": [
{
"timeinterval": "2-3", "successcount": 5,"errorcount": 6
},
{
"timeinterval": "3-4","successcount": 6, "errorcount": 7
},
{
"timeinterval": "5-6", "successcount": 8, "errorcount": 9
},
{
"timeinterval": "7-8", "successcount": 9, "errorcount": 10
},

]

},
{
"orgname": "MYORG3",
"successcount": 2,
"errorcode1": 2,
"errorcode2": 2,
"errorcode3": 2,

"chartdata": [
{
"timeinterval": "2-3", "successcount": 5, "errorcount": 6
},
{
"timeinterval": "3-4", "successcount": 6,"errorcount": 7
},

{
"timeinterval": "5-6", "successcount": 8, "errorcount": 9
},
{
"timeinterval": "7-8", "successcount": 9, "errorcount": 10
},

]

}
]

});




Ext.define('Ext.chart.theme.myTheme', {
extend: 'Ext.chart.theme.Base',
constructor: function(config) {
this.callParent([Ext.apply({
colors: ['#800000','#009900']
}, config)]);
}
});



Ext.create('Ext.grid.Panel', {
title: 'SIPR Ingest',
name : 'task',
store: store,
width: 1900,
height: 950,
renderTo: Ext.getBody(),
columns: [{
text: 'ORGNAME',
width: 150,
dataIndex: 'orgname'
},{ // chart column
xtype: 'itscomponentcolumn',
text : 'Chart',
width: 200,
// dataIndex: 'done',
dataIndex: 'time',

// HOW do I pass the Nested object here?
items: function(value1, value2, value3) {
return {


xtype: 'chart',
width: 200,
height: 150,
style: 'background:#fff',


store: Ext.create('Ext.data.Store', {
storeId:'ingestStore',
fields:['timeinterval', 'errors', 'success'],
data : [{timeinterval: value1}, {errors: value2}, {success: value3} ] // This need ot be changed based on how we can access the nested chartdata
}),
id: 'Barchart',
theme: 'myTheme',
animate: true,
shadow: true,
// store: store,
background: {
fill: '#3333FF'
},

axes: [{
type: 'Numeric',
position: 'left',
fields: ['errors', 'success'],
title: false,
grid: true,
hidden: true
}, {
type: 'Category',
position: 'bottom',
fields: ['timeinterval'],
hidden: true

}],
series: [{

type: 'column',
axis: 'left',
gutter: 0,

style: {
width: 10
//<-- Specify you Column width here
},
xField: 'title',
yField: ['errors', 'success'],
stacked: true,


tips: {
trackMouse: true,
renderer: function(storeItem, item, sprite, record, attr, index, store) {
this.setWidth(100);
this.setHeight(50);
var label = item.value[1] == storeItem.data.errors ? 'errors' : 'success';
this.setTitle(label + '<br />' + item.value[1]);

}
}
}
]

}
}
}


,{
text : 'Success Count',
width: 160,
dataIndex: 'successcount'


},{
text : 'Error Code 1',
width: 160,
dataIndex: 'errorcode1'

},
{
text : 'Error Code2',
dataIndex: 'errorcode2',
width: 200

},

{
text : 'Error Code3',
dataIndex: 'errorcode3',
width: 200

},

{
text : 'Timeinterval',
dataIndex: 'chartdata.time',// I tried accessing the data even in a grid column it does not work
width: 200

}


]
});
});


When the store loads , it has the following structure
data
[Object { orgname="USMC", successcount=2, errorcode1=2, more...}, Object { orgname="ARMY", successcount=2, errorcode1=2, more...}]
0
Object { orgname="MYORG1", successcount=2, errorcode1=2, more...}
chartdata
[Object { timeinterval="2-3", successcount=5, errorcount=6}, Object { timeinterval="3-4", successcount=6, errorcount=7}, Object { timeinterval="5-6", successcount=8, errorcount=9}, Object { timeinterval="7-8", successcount=9, errorcount=10}]
0
Object { timeinterval="2-3", successcount=5, errorcount=6}
errorcount
6
successcount
5
timeinterval
"2-3"
1
Object { timeinterval="3-4", successcount=6, errorcount=7}
errorcount
7
successcount
6
timeinterval
"3-4"
2
Object { timeinterval="5-6", successcount=8, errorcount=9}
errorcount
9
successcount
8
timeinterval
"5-6"
3
Object { timeinterval="7-8", successcount=9, errorcount=10}
errorcount
10
successcount
9
timeinterval
"7-8"
errorcode1
2
errorcode2
2
errorcode3
2
orgname
"USMC"
successcount
2
1
Object { orgname="MYORG2", successcount=2, errorcode1=2, more...}
chartdata
[Object { timeinterval="2-3", successcount=5, errorcount=6}, Object { timeinterval="3-4", successcount=6, errorcount=7}, Object { timeinterval="5-6", successcount=8, errorcount=9}, Object { timeinterval="7-8", successcount=9, errorcount=10}]
errorcode1
2
errorcode2
2
errorcode3
2
orgname
"MYORG2"
successcount
2