PDA

View Full Version : Component Column - Components in Grid Cells



skirtle
21 Sep 2011, 11:49 PM
http://skirtlesden.com/ux/component-column

I've written an extension to Ext.grid.column.Column that allows full-blown ExtJS 4 components to be returned from the renderer function. I know a lot of people have written custom code to do this sort of thing but as far as I'm aware no-one has ever wrapped it up in a reusable class.

28495

The technique will be familiar to anyone who has tried to do it themselves: render the grid without the components then slip the components in afterwards. Beyond doing the obvious I've also tried to put in some size management and logic for doing component destruction.

Performance for a small number of records is absolutely fine but it should come as no surprise that it doesn't scale particularly well. The age-old technique of faking components using some HTML and CSS remains vastly superior if you need performance with a moderately large number of records. If anyone has any suggestions for improving performance that would obviously be welcome.

I hope that what my extension lacks in scaling it makes up for in saved development time. There are some demos if you follow the link but, as a taster, the code for rendering a combobox might look something like this:


Ext.create('Ext.grid.Panel', {
...
columns: [{
...
dataIndex: 'status',
xtype: 'componentcolumn',
renderer: function(status) {
return {
...
store: ['Available', 'Away', 'Busy', 'Offline'],
value: status,
xtype: 'combobox'
};
}
}]
});

The renderer in this example returns a config and xtype but it could also return the actual component.

In the demos I show checkboxes, textfields, progressbars and buttons, though in my test cases I have it working with all sorts of other components.

For reference, the closest existing UX that I'm aware of is Condor's ComponentListView for ExtJS 3:

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

SMMJ_Dev
23 Sep 2011, 4:20 AM
Awesome! I can't wait to try this out. I saw your CTemplate as well, looks good!

siebe vos
18 Jan 2012, 8:19 AM
Indeed an awsome component! Many thanks!=D>

I have a problem with the componentcolumn being used in a grid with a cellediting plugin. When I use a checkbox xtype in the renderer for the componentcolumn, the store's record is not updated (getUpdatedRecords() returns nothing). I also listen to the 'update' event of the store and that one is not fired. When I modify another column using an editor config (as also was this column previously), I receive the stores update event and can see that the records field value of the componentcolumn defers from what I see on the screen. Configuring the same column as an editor with a checkbox xtype the record's fields are updated (was my previous config).

Forgot to tell:
ExtJs version: 4.0.7
Browser: FF 9.0.1, FB 1.9.0.B1

Do you know what's the problem?

Thanks!

pavanextjs
18 Jan 2012, 10:37 AM
Hi Skirtle,

Nice component. However when i tried to use this in my ExtJS V4.1.0Beta code, it is giving me errors. Can you confirm if this works for ExtJS V4.1.0Beta?

When i debug the code it is failing in CTemplate.js...

SCRIPT28: Out of stack space
CTemplate.js?_dc=1326912145867, line 90 character 13



if (me.pollId) {
clearTimeout(me.pollId);
}

Thanks in advance.
Pavan.

skirtle
18 Jan 2012, 6:01 PM
@siebe vos. For a checkbox you might be better off using Ext.ux.CheckColumn, as demonstrated here:

http://dev.sencha.com/deploy/ext-4.0.7-gpl/examples/grid/cell-editing.html

However, if you did do it using a Component Column it would be something like this:


{
dataIndex: 'registered',
text: 'Registered',
xtype: 'componentcolumn',
renderer: function(val, meta, record) {
return {
checked: val,
xtype: 'checkbox',
handler: function(checkbox, checked) {
record.set('registered', checked);
}
}
}
}

skirtle
18 Jan 2012, 6:15 PM
@pavanextjs. I will send you an updated version of CTemplate that's compatible with 4.1.0-beta-1. If anyone else wants it just send me a PM. I'll do a proper release once 4.1.0 is final.

siebe vos
19 Jan 2012, 12:56 AM
Hi Skirtle,

I did not get your reply on the forum via mail. Yesterday I forgot to mention the ExtJs version and browser. After I added them to my original post, I saw that you replied. This is indeed what I needed! Many thanks!

pavanextjs
19 Jan 2012, 7:21 AM
Thanks so much Skirtle, that is working :)

hzmt
9 Feb 2012, 8:16 AM
Is there anyway to suppress the component from redrawing when the store is updated?

skirtle
9 Feb 2012, 11:33 AM
It's not easy to do that at present but I agree this would be a good feature to add. If you could let me know your use case I'll try to include it in the next version.

I think I'd do this by changing renderComponent in CTemplate. Currently it just calls the component's render method but that won't work if the component is already rendered. If that method also supported moving an existing component it should be possible to keep the same component when the grid refreshes rather than creating a new one. Without knowing your use case I don't know whether this would meet you needs.

You might be able to fake it for now by suspending events on the store but that may have other consequences.

hzmt
9 Feb 2012, 11:47 AM
The current issue I'm having is that the animated toggle component I'm adding skips animation when I toggle from 'yes' to 'no' because after the store value is updated it redraws the component.

Additionally, if I have autosync enabled on the store all the components in the grid will redraw when a toggle is.. toggled. I worked around that issue by disabling autosync.. overloading the component's onClick method and then passing the record and dataIndex into the component, then saving the record in the overloaded method instead. This also fixed the issues I was having with grids that had row editors on them.

notjoshing
17 Feb 2012, 8:43 AM
I really like this component; thank you for coding this. I've been using it in a tool in which I need to be able to get back to the record from the rendered component, in this case a date field. Any thoughts on how to get back to the grid's record and column from the component?

Josh

skirtle
17 Feb 2012, 9:13 AM
The easiest way is probably just to capture the record in the closure of whatever handler function you've written. Here's an example using a button:


{
...
dataIndex: 'active',
xtype: 'componentcolumn',
renderer: function(value, meta, record) {
return {
text: value ? 'Disable' : 'Enable',
xtype: 'button',
handler: function() {
record.set('active', !value);
}
};
}
}

If you can't use a closure (perhaps because the function is declared elsewhere like it would be in the MVC) then you could just save the record as a property on the component and grab it when you need it.

notjoshing
22 Feb 2012, 7:36 AM
Nice approach. I've tried it out and it works.

Thanks!

mankz
6 Mar 2012, 12:03 PM
Nice work! Thought: Isn't it too late to try to clean up _after_ the dom elements have all been wiped?


me.mon(view, 'refresh', me.onViewChange, me);
me.mon(view, 'itemupdate', me.onViewChange, me);


Perhaps intercepting the grid views 'refresh' method and bufferRender (or whatever it's called for single item redraw) to clean up before the dom elements are gone could be a safer bet?

skirtle
6 Mar 2012, 4:39 PM
I'm not sure I follow. Why might it be too late to destroy a component after its el is removed from the DOM? The tests I've done suggest that the components do get cleaned up using this approach. Is there a potential leak I'm missing doing things this way?

mankz
7 Mar 2012, 12:30 AM
Seems I misunderstood how the browser GC worked, I ran some tests in sIEve and couldn't find anything odd. Disregard my ramblings :)

Jeff Liotta
5 Apr 2012, 11:38 AM
My original support request thread is at
http://www.sencha.com/forum/showthread.php?192591-Using-Ext-widgets-in-Grid-cells&p=773529#post773529
(http://www.sencha.com/forum/showthread.php?192591-Using-Ext-widgets-in-Grid-cells&p=773529#post773529)
I am now able to render Ext widgets in grid cells using Skirtle's plugin, thanks!!
I am facing another problem now wherein findField is not able to find these Ext widgets embedded in grid cells?

Do you know if findField is only for form panels and NOT for grid panels? Or is this a limitation of plugin or bug or something else?

I have a main form panel (id:framework), which has another form panel (blocks container) as one of its items.
This blocks container has multiple sub blocks which are rendered in individual form panels themselves.
For one of special block types, I used grid panel instead of form panel and this grid panel has Ext widgets rendered using Skirtle's plugin.
Name-based findField works for other fields which are part of form panel but not for grid panel field.

I have to do findField at multiple places and may not always know which block row or block I am working and hence want to do search using top level form.

Please advice.

skirtle
6 Apr 2012, 2:09 AM
The fields rendered by Component column are just injected into the DOM, they aren't part of the component hierarchy. While it may look like they are children of the grid they actually aren't.

findField uses ComponentQuery behind the scenes. That walks the component hierarchy looking for suitable components.

From a quick look at how ComponentQuery is implemented, it looks like all you'd need to do is override getRefItems to return your fields. It gets a little tricky if your grid is refreshed as you'll need to make sure only the current items are returned.

I'll take a look to see if this is something that could feasibly be implemented in a future version but I'm not yet sure if it could be made to work in the general case.

Jeff Liotta
9 Apr 2012, 9:59 AM
If it not much of pain, could you please provide some sample code/class that I can use/test as starting point and let you know how it goes.
I don't have grid refresh use case currently, so I believe you are suggesting to override Ext.ComponentQuery.
But I don't see getRefItems() method in Ext.ComponentQuery but found it in Ext.form.FieldSet.


I am new to Ext JS and not overriden any Ext Core classes, so I may not be getting this.
Also Ext.ComponentQuery is singleton if that matters.

skirtle
9 Apr 2012, 10:48 AM
This example comes with a health warning. It is just an example. It doesn't manage the components properly, indeed just clicking on the column header to sort the column will trash it completely (that causes a refresh).

getRefItems is defined on AbstractContainer. We're in some pretty advanced territory here, you'll need to dig into the source code rather than relying on the API docs.

I suggest studying this example, my original comments and the ExtJS source code until you understand it. If you just copy/paste you will almost certainly shoot yourself in the foot.


var gridFields = {
name: Ext.create('Ext.form.field.Text', {
name: 'name'
}),
category: Ext.create('Ext.form.field.Text', {
name: 'category'
}),
age: Ext.create('Ext.form.field.Text', {
name: 'age'
}),
type: Ext.create('Ext.form.field.Text', {
name: 'type'
})
};

var form = Ext.create('Ext.form.Panel', {
height: 300,
layout: 'fit',
renderTo: Ext.getBody(),
width: 300,
items: [{
border: false,
xtype: 'grid',
columns: [{
dataIndex: 'fieldName',
flex: 1,
header: 'Fields',
xtype: 'componentcolumn',
renderer: function(value) {
// We could create the field here and push it into gridFields instead
// but be aware that this will happen asynchronously so we wouldn't
// be able to use findField immediately if we did it that way
return gridFields[value];
}
}],
store: {
fields: ['fieldName'],
data: [
{fieldName: 'name'},
{fieldName: 'category'},
{fieldName: 'age'},
{fieldName: 'type'}
]
},
// Overriding inline in the config, we don't call the superclass version,
// which could cause problems if the grid has other items (possibly toolbars)
getRefItems: function() {
return Ext.Object.getValues(gridFields);
}
}]
});

Ext.define('Person', {
extend: 'Ext.data.Model',
fields: ['name', 'category', 'age', 'type']
});

// loadRecord uses findField
form.loadRecord(new Person({
name: 'Thomas',
category: 'A',
age: 23,
type: 'Advanced'
}));

Jeff Liotta
9 Apr 2012, 1:19 PM
Skirtle, thanks very much for prompt response.
I will be trying this and let you know how it goes. I am creating ext widgets for grid cells from within column renderer so don't have them upfront...this is so because I am using your plugin with Ext CellEditing plugin together.
I will try this and keep you posted...thanks again for your direction.

LuckyBlade
1 May 2012, 6:51 PM
Hi. In your example textfield doesn't catch spacebar keydown. How can I add it ?

LuckyBlade
1 May 2012, 10:01 PM
Solved by adding

selType:'cellmodel', plugins:[Ext.create (http://docs.sencha.com/ext-js/4-0/#!/api/Ext-method-create)('Ext.grid.plugin.CellEditing (http://docs.sencha.com/ext-js/4-0/#!/api/Ext.grid.plugin.CellEditing)',{ clicksToEdit:1})],

skirtle
2 May 2012, 12:29 AM
The grid captures certain key presses for navigation purposes, including space. You'd need something like this:


return {
...
xtype: 'textfield',
listeners: {
inputEl: {
keydown: function(ev) {
ev.stopPropagation();
}
}
}
};

wki01
2 May 2012, 4:25 AM
@pavanextjs. I will send you an updated version of CTemplate that's compatible with 4.1.0-beta-1. If anyone else wants it just send me a PM. I'll do a proper release once 4.1.0 is final.

Hello
can you post the version for 4.1?
thanks

bazis
10 May 2012, 4:25 AM
waiting for 4.1 version too

skirtle
10 May 2012, 5:21 AM
I'll get it released as soon as I can.

If you want to try a quick fix then just switch round apply and applyTemplate in CTemplate. The dependencies have switched in 4.1 and it causes a stack overflow.

There are a handful of other edge cases that I'll have fixed in the proper release but that quick fix should get it working in the majority of cases.

bazis
11 May 2012, 6:45 AM
Changed
this.createAlias('apply', 'applyTemplate'); to
this.createAlias('applyTemplate', 'apply');
Firefox don't crash anymore, but plugin don't work - I see [object Object] instead of my components (buttons)

skirtle
11 May 2012, 7:03 AM
Line 26, you need to rename applyTemplate to apply or you'll be aliasing the wrong method.

bazis
12 May 2012, 4:09 AM
Thanks for reply, this solution works, but unstable for my case.
Here my grid with buttons 35157
It is in card layout, and somtimes after hide/show events it is shows like this: 35158
After resize panel buttons apears. Need to insert doLayout() somewhere?


Sometimes it looks like this: 35159 and resize don't help.
On Ext 4.0.7 everything worked fine, after I wrote small override in Ext.layout.component.AbstractDock afterRemove method :)

UPD: if set button height, works fine. "scale:large" don't work.

liuxing_sc
23 May 2012, 8:34 PM
thanks. this is what we need really. but still waiting for your 4.1 version :)

silverasm
1 Jun 2012, 10:08 AM
Changed the alias line at the bottom, and renamed on line 26.

link41489
1 Jun 2012, 1:02 PM
Is there anyway to suppress the component from redrawing when the store is updated?


It's not easy to do that at present but I agree this would be a good feature to add. If you could let me know your use case I'll try to include it in the next version.

I think I'd do this by changing renderComponent in CTemplate. Currently it just calls the component's render method but that won't work if the component is already rendered. If that method also supported moving an existing component it should be possible to keep the same component when the grid refreshes rather than creating a new one. Without knowing your use case I don't know whether this would meet you needs.

You might be able to fake it for now by suspending events on the store but that may have other consequences.

Is the slowness of the grid refresh due to the issue of the component in the grid being redrawning? I haven't notice this issue with Chrome or Firefox using about 200 records. But in IE9, its horrible. It takes about 15-20secs for the grid to reflect the store filter. Is this just a limitation with IE itself, or is there a way to improve the performance in IE?

jconcept
18 Jun 2012, 1:28 PM
I would like the "Thomas Edit(button)" example CTemplate, but in a column grid. I am trying but something is wrong with my code because doesn´t work. ¿What I have to put into Ext.Fly funtion?
Any help?


var template = Ext.create('Skirtle.CTemplate', '<div>',
'{label} {button}',
'</div>'
);

template.overwrite(Ext.fly(...), {
label: 'Thomas',
button: Ext.create('Ext.button.Button', {
text: 'Edit'
})
});

skirtle
19 Jun 2012, 10:29 AM
I would like the "Thomas Edit(button)" example CTemplate, but in a column grid. I am trying but something is wrong with my code because doesn´t work. ¿What I have to put into Ext.Fly funtion?

CTemplate and Component Column are separate extensions and it's important not to confuse the two. While a Component Column does use CTemplate to achieve the desired effect it is largely an implementation detail. You should just need to return your components from the column's renderer, there's no need to start manipulating the underlying CTemplate directly.

Ext.fly returns an element and you aren't working with elements directly in the case of a column. Take a look at the Component Column examples instead.

To achieve the label and button effect in a column you'd need to return a wrapper container from the renderer that contains both components with a suitable layout. There are other ways to do it but that's the safest with respect to resizing and destruction management. Theoretically you can manipulate the CTemplate and return all sorts of exciting things from the renderer but that's really just making things difficult for little benefit.

rpweb.batman
19 Jun 2012, 11:15 AM
If you have an editable field component inside the component column, you cannot use the arrow keys or space bar while editing the field value as those are swallowed by the grid itself for keyboard navigation of the grid. Your first example on http://skirtlesden.com/ux/component-column demonstrates this pretty clearly. Is there any way to get around this issue?

skirtle
19 Jun 2012, 11:26 AM
If you have an editable field component inside the component column, you cannot use the arrow keys or space bar while editing the field value as those are swallowed by the grid itself for keyboard navigation of the grid. Your first example on http://skirtlesden.com/ux/component-column demonstrates this pretty clearly. Is there any way to get around this issue?

See here:

http://www.sencha.com/forum/showthread.php?148064&p=793100&viewfull=1#post793100

I'll update the demo when I release 1.1.

jconcept
19 Jun 2012, 1:25 PM
To achieve the label and button effect in a column you'd need to return a wrapper container from the renderer that contains both components with a suitable layout

This work...
Thanks a lot..

crocop21
26 Jun 2012, 7:38 AM
Hi i am trying to use the extension with ext-4.1.0 but when started its show me this error in chrome Uncaught RangeError: Maximum call stack size exceeded

and in firefox is colapse and down

skirtle
26 Jun 2012, 7:59 AM
@crocop21. Please take a look at page 3 of this thread. You'll need to switch around the dependencies between apply and applyTemplate in CTemplate.

crocop21
26 Jun 2012, 8:29 AM
@crocop21. Please take a look at page 3 of this thread. You'll need to switch around the dependencies between apply and applyTemplate in CTemplate.
Already did but still, CTemplate line 26 apply: function(values) {

and line 175 this.createAlias('applyTemplate', 'apply');

skirtle
26 Jun 2012, 8:33 AM
That should be all it needs to fix it. I suspect you have a caching problem. Could you check the script source in your debugger to make sure it's loading the correct file?

crocop21
26 Jun 2012, 8:58 AM
That should be all it needs to fix it. I suspect you have a caching problem. Could you check the script source in your debugger to make sure it's loading the correct file?

Yes, have a look pls..

365453654636547

skirtle
28 Jun 2012, 1:33 AM
A bit difficult to tell what's going on. From those screenshots it's clear that you've been renaming my classes and my guess would be that you've got another copy lying around somewhere that is being picked up. It should be fairly easy to tell what's going on using some breakpoints and a debugger. Try putting a breakpoint in the apply method of CTemplate and see what happens.

You might also like to take a look at the stacktrace. It'll be crazily long but just the bit near the top should give you a hint about why the infinite recursion is happening.

fredy_dk88
9 Jul 2012, 9:43 AM
Hi..
i'm newbie in extjs and
I'm looking for a tip to solve a problem with an extjs grid panel. The situation I'm facing is the following :
i have a grid panel with a number of columns and one column with numberfield type.i want to set the minValue and maxValue for the column but it's differrent for each row. i try to get the cell type but i can't get numberfield type. Does anyone know how to solve this problem?can i use the component column to solve this?

thanks,
Regards Fredy.

csaparna
10 Jul 2012, 10:32 PM
Hi..

Can I use 2 or more xtypes with column component?? Reason - I need to have more than 2 text fields (2 editors ) in a single column of my editor grid... Can I achieve this using Column Component?

skirtle
11 Jul 2012, 8:43 AM
@fredy_dk88. You face a choice between using the built-in editing plugins or this UX. I think the scenario you've described could be achieved using either approach. Personally I would always advise using the built-in plugins if they meet all your requirements but the Component Column can be used in many cases where those plugins just aren't applicable.

In the case of the minValue/maxValue you should be able to do it using CellEditing. If you listen on the beforeedit event and tweak the numberfield based on the passed record I see no reason why it wouldn't work:

http://docs.sencha.com/ext-js/4-1/#!/api/Ext.grid.plugin.CellEditing-event-beforeedit

If you go down the Component Column route the approach would be to return a different numberfield from the renderer based on the record passed to the renderer function. That bit would be quite easy but you'd also need to manage updating the underlying record yourself, something the editing plugins do automatically. The button/progressbar example on my website is probably the one to study if you want to go for this option.

skirtle
11 Jul 2012, 9:04 AM
@csaparna. You can't return multiple xtypes for the same cell but you can achieve the desired effect. Just return a container with both textfields in it and a suitable layout.

I'll give some thought to adding a new demo for this as it seems to be a popular request.

fredy_dk88
12 Jul 2012, 8:11 AM
Thanks Skirtle..i try use beforeedit event as you suggest and it's work great and easy to implement, yesterday i just focus to get the column or the cell type and forget using an event..after i use the event,it's working..:D

LarssaAndin
20 Aug 2012, 8:00 AM
I'm using those lovely component for my, quite complicated, grid and so far it works extremely well.
I've managed to add editing using the standard CellEditing plugin and it works fine for my normal cells.

The problem I have is that I want to be able to display a combo box in some edit cells but only when the user starts editing the cell. If it would be column specific this would be easy to accomplish, but the requirement says that it has to be configurable on a cell level.

The question is, how do I accomplish this dynamic selection of edit component? I can easily add configuration to the cell record, but I don't really understand where to add the controlling code that will use this config?

skirtle
20 Aug 2012, 8:24 AM
If your question is about the CellEditing plugin I suggest starting a new thread in the Q&A forum. I see no reason why you couldn't update the contents of the combobox's store in a beforeedit listener.

To achieve something like this with Component Column I would use the renderer to output a container and dynamically add a combobox on the click event. This could get quite complex as you'd need to manage many of the features of the CellEditing plugin yourself. Hiding the combobox and keyboard navigation are two obvious pain points.

Component Column is not intended as a direct replacement for the built-in editor plugins though it is often used in that way. Component Column just provides a convenient way to get a component into a grid cell. Editing is much more than that.

Sadd
29 Aug 2012, 12:17 PM
Hi very nice plugin, really usefull.

I have a question, i have a container with 2 items on it, one textfield, one combobox. I need to fill this items with info from one field of my store. Something like this:

store = [{id: "3", Version: "123,FX"}]

I want to render 123 in the textfield and FX is one of the values of combobox store. In the same way i need if textfield or combo changes impact this change in the store. Can you give me some help here?

Thanks,
Regards.
- Sadd

skirtle
29 Aug 2012, 1:46 PM
Personally I think I'd write my models to split up that version if the two parts are really separate.

That aside, off the top of my head it might look something like this:


dataIndex: 'Version',
renderer: function(value, meta, record) {
var version = value.split(',');

return {
xtype: 'container',
layout: ...,
items: [
{
value: version[0],
xtype: 'textfield',
listeners: {
blur: function(field) {
record.set('Version', field.getValue() + ',' + version[1]);
}
}
}, {
...
value: version[1],
xtype: 'combobox',
listeners: {
blur: function(field) {
record.set('Version', version[0] + ',' + field.getValue());
}
}
}
]
};
}

Completely untested but hopefully it'll give you some ideas. Managing focus strikes me as an obvious pain point. If you try to jump from one field to another the blur listener will cause a grid refresh and remove the focus on the new field. Depending on how and when you want the models updated you may want to use some alternative to a blur listener (e.g. if there's a save button you could put that logic in there rather than updating each record on blur). You could also directly update the data property rather than using set but that could cause other problems depending on how your records are being used.

Sadd
29 Aug 2012, 2:23 PM
Ok i see what is the way to achive this, thanks a lot for your help :).

- Sadd

LuckyBlade
5 Sep 2012, 1:13 AM
Hi! I'm using version 4.1.1. Since switching applyTemplate to apply all works great except one. After adding several elements Grid doesn't increase size. If I add for example height: 1000 to Grid config I see all elements, but fixed height it's not acceptable. Any suggestions how can I fix it?

38478

skirtle
5 Sep 2012, 4:06 AM
From what you've said it sounds like you're trying to use auto-height for grids. Not sure the framework officially supports that but it should be possible to make it work.

It's also not entirely clear what you mean by 'adding several elements'. I assume by 'elements' you mean 'rows' but I'm not sure whether you just mean that you have a lot of rows or whether you're describing a phenomenon that only occurs as a result of adding rows dynamically.

My guess would be that injecting the buttons is causing the grid view to increase in height but the framework is oblivious to this height change, so the surrounding layouts aren't heighting their containers correctly. You might want to try calling updateLayout to kick it into resizing everything. You may need to do that on a slight delay to ensure it happens after the injection of the buttons.

More than that and I'd need a proper test case.

LuckyBlade
5 Sep 2012, 9:05 AM
Yes, you are right and understood what I mean. I want to use auto-height. "Elements" the same as "rows".
Firstly, I'm creating a Grid and after that I'm adding elements to Grid's store. I don't know how many elements I need to add. If Grid hasn't got ComponentColumn doesn't matter how many rows are adding, Grid resize correctly, doing auto-height.
If Grid contains ComponentColumn after adding 1 - 5(it depends on height components) rows Grid resize right. Adding 6 or more rows you can see on previous picture.
I notice that If resize browser window Grid are increasing height to necessary and showing all content normally. UpdateLayout to viewport doesn't help.

Problem appears after updating Ext from 4.0.7 to 4.1.1

LuckyBlade
5 Sep 2012, 10:12 AM
Please, see the example and try collapse Grid.


var columns = [];
var col1 = {
flex: 1,
dataIndex: "col1"
}
columns.push(col1);
var col2 = {
flex: 1,
xtype: 'componentcolumn',
hideable: false,
renderer: function (value, metaData, record) {
return Ext.create(Ext.Button, { text: "test" });
},
dataIndex: "col2"
}
columns.push(col2);
var store = Ext.create('Ext.data.Store', {
fields: ["col1", "col2"]
});
var gridPanel = Ext.create('WyaClient.items.view.evo.Panel', {
autoShow: true,
autoScroll: true,
collapsible: true,
animCollapse: true,
store: store,
//height: 1000,
frame: true,
renderTo: Ext.getBody(),
columns: columns
});
for (var i = 0; i < 20; i++) {
gridPanel.getStore().add({
col1: i,
col2: ""
});
}

skirtle
5 Sep 2012, 11:12 PM
Thanks for the test case.

It needs a call to updateLayout to accommodate the height change. To make things a little easier I've bundled it into a patch:


Ext.define('Skirtle.grid.column.ComponentPatch', {
override: 'Skirtle.grid.column.Component',

onViewChange: function() {
this.callParent();

this.updateGridLayout();
},

updateGridLayout: Ext.Function.createBuffered(function() {
this.up('tablepanel').updateLayout();
}, 10)
});

The buffering isn't strictly required but without it the layout will be run for every row, which is a bit excessive.

LuckyBlade
10 Sep 2012, 12:36 AM
Thank you for patch, it works! But there is something strange. Firstly, I change code like this:


// View has changed, may be a full refresh or just a single row
onViewChange: function () {
var me = this,
tpl = me.tpl;


if (tpl.isCTemplate) {
// No need to wait for the polling, the sooner we inject the less painful it is
tpl.injectComponents();
}


// A view change could mean scrollbar problems
me.redoScrollbars();


me.performGC();
//Patch for 4.1.1
Ext.Function.createBuffered(function() {
this.up('tablepanel').updateLayout();
}, 10)
//end patch
},


and nothing is change...After tha I try this :


// View has changed, may be a full refresh or just a single row
onViewChange: function () {
var me = this,
tpl = me.tpl;


if (tpl.isCTemplate) {
// No need to wait for the polling, the sooner we inject the less painful it is
tpl.injectComponents();
}


// A view change could mean scrollbar problems
me.redoScrollbars();


me.performGC();
//Patch for 4.1.1
this.updateGridLayout();
//end patch
},
//Patch for 4.1.1
updateGridLayout: Ext.Function.createBuffered(function() {
this.up('tablepanel').updateLayout();
}, 10),
//end patch


and Grid become resize correctly.

In addition, after updating a page, on millisecond it's possible to notice that firstly Grid show all raws, after that Grid hide some rows, and patch force it to show raws again. It could be a way to fix bug without UpdateLayout, doesn't it ? I think the reason is in hiding raws

skirtle
11 Sep 2012, 6:19 AM
There's actually no need to edit the code directly, my patch was written so that you can have it alongside the original code.

In your first attempt to change the code you're creating a buffered function but never invoking it. No great surprise that it made no difference.

Your second attempt is much closer to my original patch.

I'm not sure I follow your final comment. I think you're saying that you're observing a brief delay in the update where the rows are momentarily hidden and want to know how to fix that? While there may be some specific hacks to work around the problem I think re-running the layout is the only way to fix the sizing problems in the general case. You could try removing the buffering but I suspect performance will die for more than about 5 rows. Another option might be to use a more intelligent technique for determining when to re-run the layout, not just a simple buffering. I guess it could monitor whether or not there are components left to inject and run the layout when they're all done.

Another option might be to suspend layouts when creating the grid and only resume them after the components have been injected. That may save you a number of layout runs and prevent the problem you're seeing without the need for patching.

LuckyBlade
11 Sep 2012, 7:47 AM
Thanks! You're right, I've made mistake in patching and try to do something with delay.

LuckyBlade
12 Sep 2012, 10:07 PM
Hi. In IE there are errors:

SCRIPT438: Object doesn't support property or method "removeEventListener" ext-debug.js, line 9129 symbol 25
SCRIPT5007: Unable to get value of property "parentNode": object is null or undefined ext-debug.js, line 14418 symbol 17.

Test case:


var columns = [];
var col1 = {
flex: 1,
dataIndex: "col1"
}
columns.push(col1);
var col2 = {
flex: 1,
xtype: 'componentcolumn',
hideable: false,
renderer: function (value, metaData, record) {
return Ext.create("Ext.form.ComboBox");
},
dataIndex: "col2"
}
columns.push(col2);


var store = Ext.create('Ext.data.Store', {
fields: ["col1", "col2"]
});
var gridPanel = Ext.create('WyaClient.items.view.evo.Panel', {
autoShow: true,
store: store,
frame: true,
renderTo: Ext.getBody(),
columns: columns
});
gridPanel.getStore().add({
col1: 0,
col2: ""
});


First error repeats if you click on sortable header. Second error appears with minute delay. Do you have any suggestion how fix it? If you try previous test case with button there is no error.
(browser IE9, doc IE9)

divya.booravalli
15 Nov 2012, 11:29 AM
This is awesome, however is there a way to just use this type to certain cells in the grid, Like only the first row of the grid should have the combo box.

Thanks.

skirtle
16 Nov 2012, 10:07 PM
@divya.booravalli. It depends. If you just want to return strings for the other rows then that shouldn't be a problem, the renderer is just like a normal column in that regard. You can grab the rowIndex as one of the arguments and switch accordingly.

However, if you want the other rows to behave like custom column types, like an Action column, then that'd be much more difficult.

It sounds to me like you don't really want the first data row to be comboboxes, you're just looking to insert some comboboxes between the grid's header and view. It may well be possible to do that without hijacking the first row of the gridview but I haven't tried myself.

kbalam
6 Dec 2012, 12:03 PM
Hi.

some idea for edit the Component class?? I need pass the "scope" property for «this» reference inside the renderer function.

But i'm some little lost. :P

joshcastaneda
19 Dec 2012, 9:06 AM
Hi,

I'm trying to modify your component.js to handle the following scenario. I have a gridpanel and am using your componentcolumn as in your example:



DestinationModel = Ext.define('DestinationModel', {
extend: 'Ext.data.Model',
fields: [
...
{name: 'id', type: 'string'}, // value
{name: 'name', type: 'string'}, // visible to user
...
]});
...
Ext.define('DestinationStore', {
extend: 'Ext.data.Store',
model: 'DestinationModel'
});
var IpDestStore = Ext.create('Ext.data.Store', {
model: 'DestinationModel'
});
var NonIpDestStore = Ext.create('Ext.data.Store', {
model: 'DestinationModel'
});
...

{dataIndex:'ipDestination', xtype: 'componentcolumn', renderer: function(dest){
return {
store: IpDestStore,
value: dest,
xtype: 'combobox'
};
}},
{dataIndex:'nonIpDestination', xtype: 'componentcolumn', renderer: function(dest){
return {
store: NonIpDestStore,
value: dest,
xtype: 'combobox'
};
}}

and I am trying to show a pair of combo boxes only on the selected row. On the select event for the gridpanel, I want to show the comboboxes and on the deselect I want to show a string of the value that would show in the combobox. Where should I start in order to achieve this? Component.js? Should I modify this renderer function right here on the column object?

Thanks,
Josh

skirtle
19 Dec 2012, 10:05 AM
@joshcastaneda.

From your description I think I'd use the standard RowEditing plugin instead:

http://docs.sencha.com/ext-js/4-1/#!/api/Ext.grid.plugin.RowEditing

The inline demo near the top of the docs does something very similar to what you're describing.

If you still want to use Component Column there are a number of ways to approach it. I don't think it's necessary to modify the extension code directly.

The simplest is to use CSS. Return both the combobox and text (wrapped in a container) and then use a suitable CSS selector to show/hide the correct entry with display: none.

Another approach might be to store the selection status in a hidden field of the records. When a row is selected it can call set on the record to update whether it is selected. This has two consequences. Firstly it'll force the grid view to refresh that row, which will ensure the renderer gets called. Secondly, it'll give you a field in the record that you can grab inside the renderer to decide whether to return a combobox or text. There are a few potential pitfalls with this approach. Firstly, you've got to add an extra field to your model that doesn't belong there, especially if the records are shared. Secondly, keeping the field in sync with the selection model could be tricky (though it may just work, difficult to say).

Another way might be to grab the selection model directly from within the renderer function to determine what to return. Then wire up the selection model's events to call refreshNode on the grid view to force the renderer to be called when selection changes.

alvita
27 Dec 2012, 3:00 AM
hi Skirtle~
thanks your component, it's really useful!
But I am stuck on this problem~
if I want to put cascade combobx in two cell
after rendering how to get each of combobox ?
I tried the way like ..grid.down('combo') but in vain
could you give me some hint for solving this problem?
thanks for your kind help in advance:)

skirtle
28 Dec 2012, 1:30 AM
@alvita. The current version doesn't wire up component queries to the column's children. There's a post discussing how to do that here:

http://www.sencha.com/forum/showthread.php?148064&p=775588#post775588

However, my first thought is that this isn't the right way to achieve cascading comboboxes. Rather than having the two comboboxes talk to each other directly just have the first combobox update the row's record when a value is selected. That'll cause a refresh of the row and you can render the second combobox based on the value in the record.

johanhaest
30 Jan 2013, 4:18 AM
Is it possible to share your version of CTemplate for 4.1 ?
We have the same out of stack exception.

carlov
6 Feb 2013, 7:20 AM
Hi
i am trying to use componentcolumn in a grid which has dynamic model




listeners : {
'metachange' : function(store,meta){
grid.reconfigure(store , [{xtype : 'componentcolumn',
header:'blabla',
dataIndex : 'bla_bla',
renderer : function(){return {
text: 'Delete',
xtype: 'button',
handler: function() {
}
};
},
{},
...,
{}]);
}
}


and it doesn't work, in the way that i get [object Object] where i should get the button.
Any idea?
Thx

skirtle
7 Feb 2013, 2:54 AM
@carlov. I've tried this against 4.1.0, 4.1.1 and 4.1.2 and it works fine in all cases.

If you could extract a complete, minimal test case then feel free to send it to me via PM. If we find anything worth sharing I'll report back to this thread.

wrowan
7 Feb 2013, 5:21 AM
I realize I am in the wrong forum, but I haven't been able to find a similar solution for Ext JS 3.4. Any thoughts on what I might be able to do would be greatly appreciated.

Thanks!

UPDATE: I ended up going with an editable grid rendering a "select" button and expanding the combo box on focus, loading the store in the beforeedit event of the grid. It isn't quite as clean as this solution, but passed acceptance testing...

carlov
7 Feb 2013, 9:08 AM
yes it works, it was my mistake; i assigned the renderer into grid reconfigure event listener (which fires after the reconfiguration).
Thanks for you time skirtle!

skirtle
9 Feb 2013, 4:32 AM
@Lukappa. That is a different extension. I believe you were looking for Its.grid.column.Component:

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

Lukappa
9 Feb 2013, 4:45 AM
Hi skirtle, you are right!
I'm sorry for my mistake...

Dev@QLP
15 Feb 2013, 1:35 PM
I think I'd do this by changing renderComponent in CTemplate. Currently it just calls the component's render method but that won't work if the component is already rendered. If that method also supported moving an existing component it should be possible to keep the same component when the grid refreshes rather than creating a new one. Without knowing your use case I don't know whether this would meet you needs.

@skirtle: Thanks so much for these awesome user extensions! I wasn't sure if I should reply here or on the post for CTemplate but do you have any more specific ideas on how to avoid the components from being destroyed and recreated after each view update? I have a small grid with a few regular columns, 2 component columns and a check column (ux). I have everything working as I want it, I just need to work on performance and I'm not that familair with how the internals of the grid refreshes work. Any help would be appreciated.

mikih
20 Feb 2013, 3:26 AM
Hi folks,

I am using the componentn coluns as a workaround for e.g. sencha touch dataviews with useComponent or as people might know itemrenderer from flex.

I have a list of items which act as a multi select menu. Inside each item are more buttons that need interaction... I can register a click event thats working fine even though I have to use 'button[action="deliveryDetails"]' instead of e.g. 'index menu button[action="deliveryDetails"]' as ComponentQuery is not working on the injected components...

Problem is that I can not prevent the grid selection model from selecting/deselecting the item each time I click an item inside the component...

I tried to

stopEvent() on the click but that wont help either...


Any ideas?

Last idea would be to disableSelection on the grid and handle selection myself - but that would be such a pain....


Thanks in advance


Florian

skirtle
20 Feb 2013, 4:36 AM
@mikih. Try stopping the mousedown event rather than the click event.

mikih
20 Feb 2013, 5:14 AM
Hi Skirtle,

thanks for your quick response! There is no mousedown event on the button... and on the grid it doesn't get fired

button only has mouseout, mouseover events


Cheers

Florian

mikih
20 Feb 2013, 5:19 AM
there is only a itemmousedown which is actually of type mousedown but stopPropagation() or even stopEvent() wont stop it from selecting it.

I also tried to stop the select event itself...


But as I understand it I need to stop the mousedown event from the button inside from bubbling up the stack?

skirtle
20 Feb 2013, 5:29 AM
You need to stop the mousedown event on the button's element.

mikih
20 Feb 2013, 5:40 AM
there is a bug in the Button class:




// @private
onMouseDown: function(e) {
var me = this;
if (!me.disabled && e.button === 0) {
me.addClsWithUI(me.pressedCls);
me.doc.on('mouseup', me.onMouseUp, me);
}
},




:)

EDIT:
there wasnt a bug: I was irretated seeing the mouseup string in there :)

skirtle
20 Feb 2013, 5:47 AM
It looks correct to me.

mikih
20 Feb 2013, 6:05 AM
sorry I have been confused :)

I added an override to the Button class to fire the mousedown event... Got it working now :)



// @override
onMouseDown: function(e) {
var me = this;
if (!me.disabled && e.button === 0) {
me.addClsWithUI(me.pressedCls);
me.doc.on('mouseup', me.onMouseUp, me);


// add fire event
me.fireEvent('mousedown', e, me);
}
},



and then in my controller I stop the event.



...
mousedown: function(e) {
e.stopPropagation();
}
...



Thanks a lot

Florian

Tifanix
25 Feb 2013, 6:38 PM
Hey, I was trying to test the component in grid, but I get the error "too much recursion".
Can you help me out a little with this?... i try to put this (like in your example) inside one of my colums:

{text: 'Nivel 1',dataIndex: 'status', xtype: 'componentcolumn',
renderer: function(status) {
return {
store: ['Available', 'Away', 'Busy', 'Offline'],
value: status,
xtype: 'combobox'
};
}
},

....Also, what i really need is to put a grid (with only one colum) inside each of the"big" grid's cells.... i think it may work just like this example but with grid instead of combobox.... am I too far from it???....
Thanks ;)

skirtle
26 Feb 2013, 1:44 AM
Hey, I was trying to test the component in grid, but I get the error "too much recursion".

You'll find this answered earlier in the thread.


Also, what i really need is to put a grid (with only one colum) inside each of the"big" grid's cells....

You should be able to include a grid but it's possible the outer grid and inner grid could clash. CSS and event listeners are obvious potential pain points but whatever the problems may be they should be solvable with a bit of tweaking. You'd have the same problems no matter how you included the nested grids.

However, if you only need 1 column then you may want to consider not using a grid at all. A dataview or a boundlist are two possible alternatives.

Tifanix
26 Feb 2013, 12:06 PM
Thanks for the quick response skirtle! I'll try a different approach not using grids and see how it goes..
Thanks again ;)

Tifanix
2 Mar 2013, 5:39 PM
Hi Skirtle,
I managed to add grids into each cell with your method... now my problem is this (IDK if It can be done)
I call the store for each grid like this:

{text: 'Nivel 1',dataIndex: 'Codigo_Asignatura', xtype: 'componentcolumn',width: 202,
renderer: function(Codigo_Asignatura) {
return {
store:'verificacion.asigPorCompetencia',
xtype: 'grid',
scope: this,
columns:[{text: 'Asignaturas', dataIndex: 'Codigo_Asignatura',width: 152}]
};
}
}

It obviously shows the same little grid inside each row of the main colum so.... how could I show different grids (different data) in each of the main rows?? is this possible?? like calling the store again in each row or something....

skirtle
2 Mar 2013, 6:03 PM
@Tifanix. The renderer function will be passed the same arguments as a normal column renderer, so that'll include things like the value for the dataIndex and the record for the row. Returning differently configured grids is perfectly possible, you just need to derive an appropriate grid config based on the arguments you're passed.

On a side note, personally I tend to avoid using store ids like you have here. You're tying yourself to a singleton store, which can be very dangerous. Stores don't just include the data, they also encompass things like sorting and filtering, so in general it isn't safe to share stores between components. Using store ids is absolutely fine if used correctly but the code you've posted implies you may be misusing them.

Tifanix
2 Mar 2013, 6:50 PM
Hi again.... thanks for the tip of the store... i'll try to change the way i'm using the ids.....
On the grid config part, could you give me some example of how could it be done... I'm not very familiar with that and i'm still kind of new to extjs so if you could give me a hand...thanks ;)

Tifanix
2 Mar 2013, 10:15 PM
...this is what i've been trying to do, i know it may be bad practice, but i'm trying to get it to work first....
I thought it might work, but it still loads the same data, it loads twice (showing what it shoud each time) but still shows the same data in both grids....


{text: 'Nivel 1',dataIndex: 'idCriterio', xtype: 'componentcolumn',width: 202,
renderer: function(idCriterio) {
if(idCriterio=='cr1Comp2'){
criterio1 = idCriterio;
return {
store:'verificacion.asigPorCompetencia',
xtype: 'grid',
itemId:'gridChica1',
columns:[{text: 'Asignaturas', dataIndex: 'Codigo_Asignatura',width: 152}],
listeners : {
render : function(gridChica1){
var storeGrid1 = gridChica1.getStore();
storeGrid1.getProxy().extraParams.criterio = criterio1;
storeGrid1.load();
}
}
};
}else if(idCriterio=='cr2Comp2'){
criterio2 = idCriterio;
return {
store:'verificacion.asigPorCompetencia',
xtype: 'grid',
itemId:'gridChica2',
columns:[{text: 'Asignaturas', dataIndex: 'Codigo_Asignatura',width: 152}],
listeners : {
render : function(gridChica2){
var storeGrid2 = gridChica2.getStore();
storeGrid2.getProxy().extraParams.criterio = criterio2;
storeGrid2.load();
}
}
};
}
}
},

what can I do to "lock" what it first loads (in the first grid) to not reloading that grid with 2nd grids data and so on.... :/

skirtle
3 Mar 2013, 6:07 AM
...this is what i've been trying to do, i know it may be bad practice, but i'm trying to get it to work first....

By using a store id you're sharing the same store instance between both inner grids. Stores aren't just configuration, they are tightly bound to the grid. Changes in the store are automatically reflected in the grid's view. If you use the same store for multiple grids you will see the same data.

Instead of sharing a store you can create your own store subclass to hold the store's configuration:


Ext.define('MyApp.store.verificacion.asigPorCompetencia', {
alias: 'store.verificacion-asigPorCompetencia',
extend: 'Ext.data.Store',

autoLoad: true,

... // Put the rest of your store config here
});

Once you've defined a class you can create multiple instances with independent data. Perhaps something like this?


{
dataIndex: 'idCriterio',
text: 'Nivel 1',
width: 202,
xtype: 'componentcolumn',

renderer: function(idCriterio) {
return {
columns:[{text: 'Asignaturas', dataIndex: 'Codigo_Asignatura', width: 152}],
xtype: 'grid',

store: {
type: 'verificacion-asigPorCompetencia', // The type matches the alias of the store

listeners : {
beforeload: function(store, options) {
options.params = options.params || {};

options.params.criterio = idCriterio;
}
}
}
};
}
}

Tifanix
3 Mar 2013, 11:38 AM
Thank you!, now it works like it should :D
I really thank you for your time, you have helped me a lot.

charvee
18 Mar 2013, 1:14 AM
I have some problem..
In rendered ComboBox's store i want 3 fields and displayfield and valuefield should be different bt it cant happend.
If i m adding values to store then it displays in rawValues instead of data array..
What should i do now??

skirtle
18 Mar 2013, 7:49 AM
@charvee. I don't really know what you're asking but it sounds like you're having problems with combobox configuration rather than Component Column.

charvee
18 Mar 2013, 9:48 PM
dataIndex : 'select',
width : 100,
height : 30,
text : 'Select',
xtype: 'componentcolumn',
renderer: function(status,meta,record) {
//console.log(record);
return {
store: Ext.create('Ext.data.Store',{
fields:[{
name:'name',
mapping:'name'
},{
name:'status',
mapping:'status'
},{
name:'id',
mapping:'id'
}]
}),
height:30,
width:100,
displayField:'name',
valueField:'status',
id:'combobox_'+record.index,
xtype: 'combobox' ,
value:status,
listeners:{
render:function()
{

this.getStore().loadData(record.data.comboData);
console.log(this.getStore());
}
}
};
}
This is my column in grid i m loading data in render function in console.log it shows me items are 1 but when i run project values are not displayed and it shows that store is empty...

Now what should i do???

if i put proxy inside store that store is loaded perfectly and combo box displays data.

skirtle
18 Mar 2013, 10:11 PM
Please use [CODE] tags when posting code.

I don't think the problem you're having is related to your use of Component Column, so this thread is not the correct place to discuss it. I suggest that you try to create a standalone combobox that exhibits the same behaviour so that you can post your question in the Q&A forum instead.

koushlendr
26 Mar 2013, 1:25 AM
Have you got any solution for this issue. Even i do have such error in IE9.
Actual thread.
http://www.sencha.com/forum/showthread.php?148064-Component-Column-Components-in-Grid-Cells&p=886534&viewfull=1#post886534

mysticav
29 Apr 2013, 3:05 PM
HI Skirtle,

Are you planning to release a version compatible with Ext. 4.2 ?

skirtle
29 Apr 2013, 4:03 PM
@mysticav. It should already work (with the tweaks for 4.1). What problem are you seeing?

mysticav
30 Apr 2013, 8:19 PM
I'nm getting same error as someone else posted on this thread. I didn't find the anwser, so again, this is the question (I'm using ExtJS 4.2)


Hi i am trying to use the extension with ext-4.1.0 but when started its show me this error in chrome Uncaught RangeError: Maximum call stack size exceeded

and in firefox is colapse and down

skirtle
30 Apr 2013, 8:25 PM
@mysticav. See page 3 of this thread. You need to change 2 lines in CTemplate.

mysticav
30 Apr 2013, 8:56 PM
Sorry skirtle, I was blind, the answer was on page 5.

I wil try your solution. Thank You.

mysticav
1 May 2013, 5:27 PM
Hi Skirtle,

I tried your fix and it works, however, in Chrome Development Tools Console, I'm getting a lot these warnings:

"[W] Obsolete"

So I commented out these lines, since they are deprecated (4.1+):

grid.invalidateScroller();
grid.determineScrollbars();


Also, I noticed that if you update a record in the grid (for example, by updating the record via record.set function), fires a row refresh event and so the fields already injected using component column plugin, are reseted.


The reason why I'm using this plugin is because I need to render different types of fields per row based on a record value.

Using the official "cellediting" ptype would be great if I could define on the fly the field type, and not just statically via editor column property, as it is normally done.

So probably, some of you guys got an idea how to use the cellediting ptype but defining the field type dinamically per row.

Thanks.

UPDATED. I found my solution. using "getEditor" property from cellediting. Now I can create a field per row. Anyways, I will keep an eye on this plugin, since it looks very interesting.

skirtle
7 May 2013, 9:00 AM
Component Column version 1.1 is now available:

http://skirtlesden.com/ux/component-column

Those upgrading from version 1.0 will also need the latest version of CTemplate.

Version 1.1 introduces support for component queries as well as fixing various bugs.

Richie1985
16 May 2013, 7:59 AM
i get this error:

TypeError: el is null
el.addCls.apply(el, arguments);


newest version with extjs 4.2

skirtle
16 May 2013, 10:19 AM
@Richie1985. I'll need more information to figure out what the problem is. If you can't provide a full test case could you at least post the config for the column? The full stacktrace, with line numbers, could also be helpful.

Richie1985
16 May 2013, 11:39 PM
hi,

here is my code:


columns: {
items: [
{
dataIndex: "id",
hidden:true
},{
dataIndex: "name"
},{
xtype: 'componentcolumn',
dataIndex: 'value'
,renderer: Ext.Function.bind(this.renderCell, this)
}
],
defaults: {
flex: 1
}
}
..............



this.renderCell = function(val, meta, rec) {
console.log(val);
if(rec.get('type')=='date'){
if(Ext.isDate(val)){
return Ext.Date.format(val,'d.m.Y');
}

};
if(rec.get('type')=='checkbox'){
return {
checked: val,
xtype: 'checkbox'
,margin: '0px 0px 0px 0px'
,handler: function(checkbox, checked) {
rec.set('value', checked);
}
};

}
return val;
};




the error comes when i click the checkbox (the value will be saved without problems) at this point: ext-all-debug.js (Zeile 30611)

thx!

skirtle
17 May 2013, 2:25 PM
When the checkbox is clicked it calls the handler function and then updates its dirtyCls. In this case the handler function is causing a grid refresh, which destroys the checkbox and creates a new one. The attempt to update the dirtyCls is then failing because the checkbox has been destroyed.

You can induce the same error with just a checkbox:


Ext.widget({
renderTo: Ext.getBody(),
xtype: 'checkbox',

handler: function(checkbox) {
checkbox.destroy();
}
});

There are many different ways to work around this. Here are a couple:


return {
checked: val,
onDirtyChange: Ext.emptyFn, // <- override the problematic method
xtype: 'checkbox',

handler: function(checkbox, checked) {
rec.set('value', checked);
}
};


return {
checked: val,
xtype: 'checkbox',

handler: function(checkbox, checked) {
// Add a delay to allow the click handling to finish before refreshing the grid
Ext.defer(function() {
rec.set('value', checked);
}, 10);
}
};

rt.karthik87
27 May 2013, 5:31 AM
Hi

It looks good. But i need something different. The same component column that watn to be available in tree column. I want a something like this.
{
xtype : 'treecolumn',
renderer :function(value....){
return : {

xtype : 'combobox',
select:function(){
record.set('','');

}
}

}

Is it possible to create components in tree column. I am surfing in net for the past few weeks. Please help me in this regard.

skirtle
27 May 2013, 7:21 AM
You could get a similar effect by putting the components in a different column of your tree but there's nothing to support injecting them into the treecolumn itself. I've not seen any UX to do that.

From a quick look at the code for treecolumn it doesn't look like it would be too difficult to get something to work. I'd try swapping in a CTemplate for the cellTpl and provide a renderer that return components. Add a bit of destruction management and that should be about it.

rt.karthik87
28 May 2013, 2:43 AM
Hi,


I tried using the component column something like this in my code

columns: [
{
xtype: 'componentcolumn',
dataIndex : 'add',
text: 'Add',
flex: 0.25,
renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
return {
checked: value,
xtype: 'checkbox',
listeners : {
'change' :function(editChkBoxId, newValue, oldValue, eOpts){
record.set('edit', newValue);
record.set('add', newValue);
}
}
};
}
},
{
xtype: 'componentcolumn',
dataIndex : 'edit',
text: 'Edit',
flex: 0.25,
renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
return {
checked: value,
xtype: 'checkbox',
listeners : {
'change' :function(editChkBoxId, newValue, oldValue, eOpts){
record.set('edit', newValue);
record.set('add', newValue);
}
}
};
}
}


if i tried to set the value in the record while changing the checkbox i am getting B is null error. Whats the reason am getting this kind of error.

skirtle
28 May 2013, 6:08 AM
@rt.karthik87. Please see this earlier post:

http://www.sencha.com/forum/showthread.php?148064&p=967292#post967292

rt.karthik87
29 May 2013, 5:10 AM
@skirtle thanks a lot. it works fine.
I am expecting the tree column which supports different renderer. Please see the earlier post.

rt.karthik87
30 May 2013, 1:34 AM
Hi,

in your website mentioned as your component column will be used only in small grid where performance is not an issue. Small grid means can you tell me the exact count of records it may support. For example if am having 500 records whether it will affect the performance?

skirtle
30 May 2013, 2:18 AM
It depends on too many things for me to put a figure on it: browser, OS, hardware, other columns, etc.

However, I would expect 500 rows to be a struggle. The only way to be sure is to try it yourself. Even if the initial rendering performance is acceptable you may find the large DOM cripples subsequent layouts.

qooleot
1 Jun 2013, 4:37 AM
"For example if am having 500 records whether it will affect the performance?"

Yes, 500 rows is generally slow (especially for older computers). If your target is chrome/ff/safari on modern computers, that is about the limit and possible, but really no more.

I tried a single componentcolumn with a button+menu on 3,000 rows and it takes 2 minutes on chrome on a new computer, and IE7 gets crushed (does not render in 5 minutes). I fixed my issue by paginating the grid to 100 rows and it then worked perfectly so thats a possible suggestion for a large row count.

Stormseeker
5 Jun 2013, 8:11 AM
I have eclipse setup to run all code in my project through JSHint and I noticed a warning about this below code (Expected a conditional expression and instead saw an assignment) and was trying to figure out the meaning.



if (item = Ext.getCmp(ids[index])) {
items.push(item);


if (deep && item.getRefItems) {
items.push.apply(items, item.getRefItems(true));
}
}


For the first if statement, are you just trying to check if the item object exists after you try and retrieve it from Ext.getCmp... I.E. would it be equal to this?



item = Ext.getCmp(ids[index]);
if (item)
{
items.push(item);
if (deep && item.getRefItems)
{
items.push.apply(items, item.getRefItems(true));
}
}

skirtle
5 Jun 2013, 9:07 AM
Yes.

extjsnewbie81
27 Jul 2013, 4:54 PM
Hi Skirtle,

I am new to ExtJS.

I am having some problem with getting reference of ComponentColumn child elements in the MVC controller.

I am using below line of code.


var columns = mygrid.getView().getHeaderCt().getGridColumns();
var directChildElements = Ext.ComponentQuery.query('columns[2] > *');


Here I am getting empty array as the value of 'directChildElements'.

Please let me know if I am doing something wrong.

Thanks

skirtle
27 Jul 2013, 10:55 PM
That second line has no chance of working. The query method is being passed a string that contains the name of a local variable but how could it possibly resolve that name to the array?

Something like this should work:


var directChildElements = columns[2].query('> *');

extjsnewbie81
29 Jul 2013, 6:52 AM
Thanks Skirtle its working for me now.

da_b0uncer
22 Aug 2013, 2:42 AM
For resizing purposes I extended the component column with this:




initComponent: function() {
this.callParent( arguments );
this.on( 'resize', function( column ) { column.up( 'grid' ).view.refresh(); } );
}


Seems a bit slow, because it's refreshing the whole grid, not only the component column.

Is there a better way?

skirtle
22 Aug 2013, 4:24 AM
I don't understand what you're trying to do. Components should automatically be resized when the column is resized.

da_b0uncer
22 Aug 2013, 4:25 AM
I see, so this is just a problem with draw components (which I'm using to generate column charts), I guess.

skirtle
22 Aug 2013, 4:57 AM
Take a look at the method setChildWidth. If you're having problems with the children resizing then that's probably the best place to start debugging. Ultimately it relies on the setWidth method of the child component.

If you're going to refresh the whole view then I'd recommend overriding onColumnResize rather than initComponent. Currently that method just forces a resize on all the children but if you're going to be re-creating them all anyway then that's just a waste of time.

da_b0uncer
22 Aug 2013, 5:02 AM
I create the draw component in the renderer function, so my first thought was this:


this.on('resize',function(column){
column.render();
});

But it only threw errors.

skirtle
22 Aug 2013, 5:21 AM
Ext.chart.Chart handles resize via an override of afterComponentLayout but from a quick look at the source I don't see any resize handling in Ext.draw.Component itself.

If you're using Ext.draw.Component directly then I think you'll either have to implement some resize logic in your component or you'll have to refresh the entire grid view.

An alternative might be to output a container from the renderer containing your chart and re-create the chart when the container is resized. However, I suspect that may prove inefficient,

rishu27
2 Sep 2013, 10:50 PM
Hi skirtle,

I have a requirement to use component column but with different controls in a column.Attaching the screenshot of my requirement. 45652
Please help me in achieving this type of functionality through Component Column.

skirtle
3 Sep 2013, 12:52 AM
Based on your screenshot I wouldn't use a grid. It appears to be a form showing the fields of a model.

However, if you were to use a grid with a component column, you'd just return a different config from your renderer function based on the values passed to the renderer.

da_b0uncer
18 Sep 2013, 11:53 PM
In a few of my grids I get a strange string inside of the component cells.


{concatI_additional_at_0tt-stdI_evalIIIareaI_inI_wildcardI_AreaIII/p100/lists/target/_I_I_I_IAreaIIISessionsIIITimestampIIIIISessions_I}


I guess this is a placeholder, which should be replaced later, but this never happens.

skirtle
19 Sep 2013, 4:43 AM
The dataIndex for the column is used in the template (effectively an XTemplate) and it's not really a surprise that a property name like that won't work. I'd imagine the slashes are being treated as division. In my experiments I get empty strings rather than the placeholder but it may vary by ExtJS version.

Could you drop the dataIndex from the column? The value would still be accessible in the renderer via the record.

Alternatively you could try mapping your field names to something a little less crazy. It's only a matter of time before you run into other problems with field names like that.

da_b0uncer
19 Sep 2013, 7:18 AM
Ah yes, I shoved it into the XTepmlate and it gave the same result...

I know, these dataIndexes suck rather much. They come from a migration of an older tool. Have to straighten them out

Thank you :)

da_b0uncer
9 Oct 2013, 1:22 AM
I have a grid with 3 component columns a paging of 20 records, all of them are draw components.
They get redrawn when I hide a column, even if the column wasn't one of these component columns.
This results in lags of a few seconds every time someone hides or shows a column.

Are there any performance tips available?

skirtle
9 Oct 2013, 5:39 AM
From what you've said, I would guess that the problem is the component columns resizing after another column is hidden.

You could try setting autoWidthComponents: false on the component columns and giving your draw components a configured width instead.

da_b0uncer
9 Oct 2013, 5:43 AM
The strange thing is, all the columns have a fixed width, so hiding one of the columns shouldn't resize any other column. Also I want my components to resize properly if a "real" resize of the column occurs. :\

skirtle
9 Oct 2013, 9:33 AM
You should try using autoWidthComponents: false to help diagnose the problem even if you don't intend to use it for real. It'll help to confirm where the performance problems lie.

Beyond that I suggest throwing profiling tools at it to try to better understand what's going on. The key questions are what is triggering the redraw, is it necessary, how often is that happening and is the redraw as fast as it could be?

da_b0uncer
9 Oct 2013, 10:08 AM
Okay, I will try it, thank you :)

jayg27
25 Oct 2013, 7:41 AM
First of all... Great component! Thanks.

I am having an issue with components not receiving focus in IE. I am using IE10, have a grid with a row of two comboboxes and a text field. When I click on a text field, for example, the field has the cursor but the component never fires the focus event.

Easy test is on your example page, http://skirtlesden.com/ux/component-column, the first example. Click on any of the name text field. Notice that the IE's built in 'X' to clear the field does not show up for every field. You have to click on it again, then which it receives focus.

Any ideas on workarounds or fixes?

Thanks,
Jay

da_b0uncer
7 Nov 2013, 2:27 AM
After profiling around I found that adding component columns blocks my UI for a few seconds.

The problem isn't how long it takes, but that I can't do anything with the UI while it happens.

46736

In this picture, the long violet layout bar at the end appears when the 4 component columns are added.
It's the time, when the rows of the grid are rendered after the data is loaded.

Suspending the layouts while this happens didn't help, because they have to be rendered at some point and 3 x 20 draw-components + 1 x 20 buttons are expensive, so I don't think this can be eliminated totally.

But it would be nice if I could stretch the process a bit to get some time-gaps where the UI is accessible, but I don't know how to accomplish this, since the actual rendering happens somewhere in the framework (ctemplate, ccolumn or extjs).

skirtle
7 Nov 2013, 8:15 AM
@da_b0uncer. A picture of a purple line doesn't give me much to work with. You need to dig in to figure out what it's actually doing. Chrome's CPU profile is usually the best way to figure out performance problems like this.

If you'd like my help trying to resolve this bottleneck then you'll need to send me a complete test case so that I can reproduce the problems you're having. You can send it to me via PM or email.

da_b0uncer
7 Nov 2013, 8:46 AM
Oh okay.

I thought the case of >60 component cells, could be a common problem. But probably it only occurs when those are filled with draw components. :D

My app is rather complex, so I will try to reproduce the problem in a simpler version.

Sorry to bother you :)

benoitp
2 Dec 2013, 12:26 PM
Hi,

Thanks for your plugin, it is a great addition to the Extjs Grid.

I encountered an issue though on IE (tested on IE9) with Ext 4.0.7 as shown in this jsfiddle : http://jsfiddle.net/cAS6e/29/

The comboboxes do not respond to changes in the textfield half of the times (try using one combo after the other). The events (blur and keydown) are not raised half of the times.

Upgrading to 4.1 solves the issue.

If not a fix (I understand 4.0.7 is somehow overdue now), could you point to why this is happening and a possible workaround ?

Thanks in advance for your help

Ben

noiks
6 Dec 2013, 3:07 PM
Any idea why will I get below error,

ReferenceError: record is not defined



xtype: 'componentcolumn',
renderer: function(value, m, record) {
return {
xtype: 'button',
handler: function() {
var r = record;
}

skirtle
6 Dec 2013, 7:04 PM
@noiks. I don't see any reason why that code would cause that error. Set your debugger to break on errors (pause on exceptions) and see what that throws up.

@jayg27 & @benoitp.

The IE focus problems are most obvious in 4.0 and 4.2, but 4.1 isn't entirely behaving itself either. The problem seems to be that the selection model is trying to give the grid row focus, which is stealing the focus away from the field. A quick experiment suggests that you can prevent this by stopping the propagation of the mousedown and click events:


inputEl: {
click: function(ev) {
ev.stopPropagation();
},

keydown: function(ev) {
ev.stopPropagation();
},

mousedown: function(ev) {
ev.stopPropagation();
}
}

It might be better to put the listeners on the el rather than the inputEl, whatever works best for you.

This will also prevent the row from being selected when the field is clicked. If you want selection without the focus problems then you're going to have to dig in yourself and do some tactical overrides on the relevant classes. Rather you than me.

For reference, Action column attempts something similar in its processEvent method. It's maybe something for me to consider in a future version of Component column, though grid gadgets in ExtJS 5 will make Component column somewhat redundant.

Alexey.Solonets
28 Dec 2013, 4:05 AM
This happens because 'record' argument is already not visible when 'handler' function is executed.



{
xtype: 'componentcolumn',
renderer: function(value, m, record) {
var rec = record;
return {
xtype: 'button',
handler: function() {
// use 'rec' here
}
}
}

skirtle
29 Dec 2013, 12:42 AM
@Alexey.Solonets.

I disagree. You don't need to introduce a local variable that references the method parameter. When the handler function is defined the parameter record is in scope and will be captured in the closure.

Alexey.Solonets
29 Dec 2013, 1:10 AM
@skirtle

Sometimes it happens and I actually still not sure why :"> :-?. Look at similar question on stackoverflow: http://stackoverflow.com/questions/12841414/ext-msg-confirm-callback-is-not-creating-a-closure

skirtle
29 Dec 2013, 5:17 AM
You'll have to forgive my scepticism but I've never observed this behaviour in any browser and it seems unlikely that something so fundamentally broken could make it into a released browser. Even if it did I can't see how a library as complex as ExtJS could possibly work with such a buggy JS engine, it'd collapse in a heap long before reaching that code.

Even more unlikely is that such a serious bug observed in October 2012 (according to that SO question) would still be present now.

If you can provide specifics (affected browser version, confirmed browser bug ticket, etc.) I'd be more than happy to change my mind.

In my opinion a much more likely, albeit uncharitable, explanation is that you're simply misinterpreting what you're seeing.

Alexey.Solonets
4 Jan 2014, 12:42 AM
@skirtle
Seems like your skepticism is pertinent. I tried to reproduce and had no luck :)

disller
6 Apr 2014, 3:21 PM
@skirtle

Thanks for the Component Column, but I found a problem for me, because my dataindex has special character, for example :, which can cause Component Column fail.

Could you please give me any suggestion to fix it except for changing the dataindex.

Thanks.

skirtle
7 Apr 2014, 4:42 AM
@disller. See earlier discussion:

http://www.sencha.com/forum/showthread.php?148064-Component-Column-Components-in-Grid-Cells&p=997560&viewfull=1#post997560

In short, just remove the dataIndex from the config and grab whatever values you need from the record passed to the renderer.