This question has the answer to adding the tooltip: Extjs4 set tooltip on each column hover in gridPanel
I have a follow up question to the most upvoted answer to t
And made this into complete configurable plugin
based solution, that requires very little configuration to use. And plays nicely with Sencha Architect.
The main motivation for researching this and getting it to work is that the DateColumn
has the renderer
config parameter marked as hidden
so that Sencha Architect doesn't allow you to modify it in the Config
panel. I understand why and it drove me to this solution, which I think is the correct one and the most maintainable and reusable in the long run.
I am using Sencha Architect 3.x and ExtJS 4.2.2, these instructions are included on how to apply these features in that environment. If you don't use Sencha Architect, you will just have to create and manage the files yourself. I find it extremely productive when working on any size ExtJS project.
First is the actual GridPlugin
:
Add a JSResource
to your project, set the url
to js/CellToolTip.js
, and then copy the following code as its contents.
Ext.define('Ext.grid.plugin.CellToolTip', {
extend: 'Ext.AbstractPlugin',
alias: 'plugin.CellQTip',
config: {
debug: false
},
init: function(grid) {
// You may not need the scope, but if you do, this binding will
// allow to preserve the scope configured in the column...
var pluginRenderer = Ext.Function.bind(this.renderer, this);
Ext.each(grid.query('gridcolumn'), function(col) {
var renderer = col.renderer;
col.renderer = renderer ? Ext.Function.createSequence(renderer, pluginRenderer) : pluginRenderer;
});
},
renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
var col = view.getGridColumns()[colIndex];
var fn = this[col.itemId];
if (fn) {
metaData.tdAttr = fn(value, metaData, record, rowIndex, colIndex, store, view);
}
return value;
}
});
Here is how you apply it to a GridPanel
:
You add what is called a Process Config function to each GridPanel
that you want to apply the plugin to:
What this does is it acts as an interceptor function and allows you to modify the config
of the Component
before it is actually applied.
processBlobInfoGridPanel: function(config) {
var ttp = Ext.create('Ext.grid.plugin.CellToolTip', {
createdOn: function(value, metaData, record, rowIndex, colIndex, store, view) { return 'data-qtip="' + value.toUTCString() + '"'; },
byteSize: function(value, metaData, record, rowIndex, colIndex, store, view) { return 'data-qtip="' + value + ' bytes"'; }
});
config.plugins = [ttp];
return config;
},
First what this does is creates the plugin
with its own config where each attribute is the itemId
of each Column
that you want to apply the plugin to.
The function that is associated with each Column
has the exact same signature as the renderer config.
Here the function implementations are short and in a single line. This is just an and example is for brevity.
createdOn
adds a ToolTip
for each Cell
in that Column
as the time in UTC
.
byteSize
adds a ToolTip
for each Cell
in that Column
that shows the raw number of bytes as a detail.
Then it adds the instance of the configured plugin to the config
of the GridPanel
and returns the instance of the config
.
In Sencha Architect I created a Column
to represent the Size
of Resources
, I wanted to show the byte size as a human readable format with the largest appropriate interval. So I added a renderer
function to do this.
I realized I was going to need this Column
on multiple GridPanel
instances so promoted it to a Class.
The way you do this is you right click on the Column
and pick Promote to Class
. Sencha Architect then creates the following code and puts it in a file in your app/view
directory with the name of the file equal to the userClassName
you specified in the Config
panel.
Ext.define('AdminApp.view.ByteSize', {
extend: 'Ext.grid.column.Column',
alias: 'widget.byteSize',
itemId: 'byteSize',
dataIndex: 'size',
text: 'Size',
tooltip: 'Byte size in human readable format',
initComponent: function() {
var me = this;
me.callParent(arguments);
},
renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
// convert bytes into a human readable format"
var bytes = value;
if (bytes>=1073741824) {bytes=(bytes/1073741824).toFixed(2)+' GB';}
else if (bytes>=1048576) {bytes=(bytes/1048576).toFixed(2)+' MB';}
else if (bytes>=1024) {bytes=(bytes/1024).toFixed(2)+' KB';}
else if (bytes>1) {bytes=bytes+' bytes';}
else if (bytes==1) {bytes=bytes+' byte';}
else {bytes='0 byte';}
return bytes;
}
});
Now the original instance of this Column
is pointing to this new Class
:
columns: [
{
xtype: 'byteSize',
itemId: 'byteSize'
}
]
Now to use this in other GridPanel
instances in Sencha Architect, just right click on the Column
instance that is linked to this new class and select Duplicate
. Then drag the duplicated instance to the GridPanel
you want to use the ByteSize
class and drop it in the list of Columns
. Then configure each cloned instance independently of the others.
Any changes to the default or behavior of the ByteClass
automatically affect all the instances.
This is a first working minimally viable solution, there are obvious enhancements that can be made. For example, I am want to fix it where it appends to metaData.tdAttr
if there is already content instead of blindly over-writing what is there.
Any enhancements will be done to this Gist on GitHub.