My first blog of the new year.. Wishing all my readers a very Happy and Prosperous New Year 2011….
Coming to the topic, I have needed to have ExtJs components in GridPanel columns many times. I have been using ExtJs components in GridPanels for sometime now, but thought of writing a blog post for it only after I saw a couple of people having trouble doing so.
Really it was more easy that I anticipated it to be, the first time I had an ExtJs component (a Button) in a GridPanel column. All that is needed is to specify a renderer for your column, create the ExtJs component in your renderer method, and return the html for the component.
You can see an example of the same below. You would notice that the third column in the GridPanel has 3 different types of components, Buttons, ProgressBars, and TextFields. You can virtually have any ExtJs component you need in the GridPanel.
Only these few lines of code were required for having the components in the GridPanel column above:
{syntaxhighlighter brush: jscript;fontsize: 100; first-line: 1; }function extjsRenderer(value) {
var id = Ext.id();
(function() {
if (value < 50) {
var bar = new Ext.ProgressBar({
height: 15,
renderTo: id,
value: (value / 100)
});
} else if (value < 75) {
var btn = new Ext.Button({
renderTo: id,
text: ‘Price: ‘ + value
});
} else {
var txt = new Ext.form.TextField({
value: value,
renderTo: id,
height: 15
});
}
}).defer(25);
return (String.format(‘<div id=”{0}”></div>’, id));
}{/syntaxhighlighter}
You would notice that the code generates a unique id (using Ext.id) and returns a div with its id set to the unique id created. It also generates the desired ExtJs component with its renderTo config option set to the id that was created. An important point to note is that the component is created after a delay. Let me explain why.
My original approach created a couple of nested divs, then instantized the desired ExtJs component specifying the inner div as the rendering target for the ExtJs component (renderTo: innerdiv) and finally returned the html for the inner div (including the tags for the inner div).
The code worked, but there was a gotcha. Some components did not render perfectly with this approach (e.g. ProgressBar) and I had to write additional code for ensuring things work. My guess is it happened because the ExtJs component was rendered to a DOM Element created via a call to document.createElement. But later, I simply returned the html for this element, and ExtJs created a new DOM element from the returned html. I used afterrender listeners to correct any issues due to this.
Then as pointed out by Eugene in the comment below, using an id and deferred rendering helped resolve any issues, and I updated the above code accordingly. In this approach, we create and return a div with a known unique id from the renderer method. Then after a delay, which ensures that ExtJs would have added the returned div to the DOM, we instantize the desired ExtJs component and use the known unique id as the rendering target (renderTo: id) for the ExtJs component. This renders the component at its desired place inside the GridPanel column, and the component behaves normally without any issues.
I am going to file a feature request to the ExtJs team requesting them to allow returning an Html/ExtJs element from column renderer methods also, in addition to the html that is now required to be returned.
The complete code for the above example is attached below.
Nice post, but seems I know more accurate solution:
{ header: “…”, dataIndex: “…”, width: 200,
renderer: function(value, meta, record) {
var id = Ext.id();
(function() { new Ext.ProgressBar({ renderTo: id, value: value, }); }).defer(25);
return ‘<span id=”‘ + id + ‘”></span>’;
} }
afterrender event handling needed only for classes adding. Proper dimensions will be calculated automatically.
Only one issue remains unsolved for me – font size after progress bar height changing. In your example row looks a bit stretched and you can safely decrease progress bar height to avoid this. But in case when progress bar has text attribute specified you will see ugly unscaled font after height changing.
Is there any other solution other than use of defer method?
Hi Rahul
ur example was of very handy to accomplish my requirement. There is a small clarification for which i think u may have an answer.
i have rendered textbox / password field based on a parameter on a gridpanel. It works perfect as per ur suggestion. Now when i submit i could not retrieve the value of the textbox/password filed. if any one could throw some light , it would be highly helpful.
Thanks in advance
Anbarasan
I like it very much..
Thank you
I have a panel in which i am putting a grid panel.
set property autoscroll:true
I get 4 values from store. i populate the grid with single column using renderer for formating. I am using similar method stated above.
The problem I am facing is, If the height of grid grows beyond panel, scroll bars are is shown.
I thing What is happening is that first panel is loaded with empty div so no scrollbars for panel, but after 200 ms i fill the rows with html / component using renderer and height increases, but panel was already painted so it doesnot gives scroll bar.
Any workaround for this??
Great! You just save me
I’m not going to lie, I think think this was possible without major hacks on the code.
Very nice, sir.
Hi Rahul,
This works great. The only catch I see, is that if you update the row via store, the values of rendered textfields using your approach are resseted. Also happens after sorting the column.
Any idea how to solve this problem ?
thanks for your code!
Hi All,
I have an Editable grid panel with multiple rows,I need to have fileupload/Mutiple fileupload for one of the column in the grid to attach the different files for each row. After selecting the files in each cell they uploaded and reference file names should be saved in the grid hidden field before submitting the editable grid
Is there any solution to upload to files and keeping the uploaded files in hidden field before submitting the entire grid
Thanks in advance
Srinivas V
Hi Rahul,
I was looking for column based serach in a grid. The requirement is such that a search text field will appear below the column name in all the columns of the grid. That text field will should search once the user hits the enter button, but only in that particular column.
I am trying to find this from many days. But I am not getting it, As I am new to ExtJs I dont know weather it is possible or not. So please suggest me some solution.
Thanks & Regards
Harsha
HI
Can u please tell me that how to Changing-empty-text-of-a-grid-when-store-is-already-empty.
Thanks
Lokesh
Hi, very nice post, plz make tutorial on extjs 4.1. I try that but that don’t working 🙁
Hey Rahul,
I am facing problem while same grid i am building in extjs 4.2 and main problem is when i m clicking on grid containing TextField,TextAres and Combobox then i am not able to enter values . i meant its loosing focus ,yes if i click two times then component is allowing me to enter Values,its stoping my delieverable work Please help me ASAP. i am looking forward for your response ,
Thanks in advance