PDA

View Full Version : Call custom function in Group Header Template



Zyrix
12 Dec 2011, 12:45 AM
I use custom renderers in my grid to display data I get from another store.

One of them is:


function genre_name(val) {
return genres.queryBy(function(rec) {
return rec.data.id == val;
}).get(0).get('genre');
}


Now I'm grouping my store of the grid and trying to customize the group titles:


var groupingFeature = Ext.create('Ext.grid.feature.Grouping', {
groupHeaderTpl: 'Genre: {[genre_name({name})]}'
});


However I get an error: Uncaught SyntaxError: Unexpected identifier

Even if I enter the parameter directly in the template like this


var groupingFeature = Ext.create('Ext.grid.feature.Grouping', {
groupHeaderTpl: 'Genre: {[genre_name(1)]}'
});


I get another error: Uncaught ReferenceError: genre_name is not defined

Why is it not possible to call the function genre_name() although it's being called by the grid for the renderer function for each column. Or is there any way I can access the values generated by the renderer function of the grid?

skirtle
12 Dec 2011, 4:39 AM
Taking these one at a time.

First, this:


function genre_name(val) {
return genres.queryBy(function(rec) {
return rec.data.id == val;
}).get(0).get('genre');
}

I assume genres is a store?

For the line rec.data.id, generally it is bad practice to access a field through the data property, use rec.get('id') instead.

Using queryBy seems excessively complicated for finding a single record. Would it not be easier just to use findRecord?


function genre_name(val) {
return genres.findRecord('id', val).get('genre');
}

Assuming id is the idProperty for your model, it would probably be even easier to use getById.


function genre_name(val) {
return genres.getById(val).get('genre');
}

Next, this:


{[genre_name({name})]}

The code inside {[...]} will just be run as JavaScript, no substitutions can be made. This is why you get that error as {name} isn't valid JavaScript.

Inside a {[...]} block you have access to a number of useful variables such as values and parent. Take a look at the docs for XTemplate for more information:

http://docs.sencha.com/ext-js/4-0/#!/api/Ext.XTemplate

Next up, this one:


{[genre_name(1)]}

If genre_name is a global function then this will work fine. Given the error you're seeing I can only conclude that genre_name isn't global and that your grid is in the right scope to see it. This is actually a good thing, you shouldn't have globals without a suitable namespace.

To call a formatting function you have a few options. One option is to save it in the formats namespace:


Ext.util.Format.genre_name = function() {
...
};

The reason for doing this is that formats have a special syntax within templates:


{name:genre_name}

An alternative is to save the function on the template itself:


groupHeaderTpl: Ext.create('Ext.XTemplate', 'Genre: {name:this.genre_name}', {
genre_name: function(val) {
...
}
});

Personally I'd usually go for this last option but if your formatting function is used throughout your application then saving it to Ext.util.Format would make it much easier to share it.

Zyrix
16 Dec 2011, 11:53 AM
Thank you very much for your detailed instructions on improving my code and solving the formatting problem. I adapted your changes and the display of the genre name works as intended now by saving my function in the Ext.util.Format namespace.

I also tried your second solution and created a XTemplate with my function inline:


var groupingFeature = Ext.create('Ext.grid.feature.Grouping', {
groupHeaderTpl: Ext.create('Ext.XTemplate', 'Genre: {name:this.genre_name}', {
genre_name : function(val) {
var rec = genres.getById(val);
return rec ? rec.get('genre') : val;
}
})
});


However this does not work and [object Object] gets displayed as the group header. As the other solution works, it's not important to know why this doesn't work, I'm just curious why ExtJS won't call the inline formatting function.

skirtle
16 Dec 2011, 4:21 PM
OK, having done a quick bit of digging I think I can explain it. From the docs for groupHeaderTpl:


Template snippet, this cannot be an actual template.

It does string concatenation internally with the provided string, so the XTemplate I created was treated as a string, giving what you described. In general the approach I suggested works fine with an XTemplate, it's just the way its used with that config option requires it to be a string rather than the template itself.

Zyrix
18 Dec 2011, 2:38 AM
Thank you for the clarification, it worked after I modified the Template to:


groupHeaderTpl: 'Genre: {name:genre_name}',
genre_name : function(val) {
var rec = genres.getById(val);
return rec ? rec.get('genre') : val;
}


I also found an interesting solution here: http://www.sencha.com/forum/showthread.php?141926-groupHeaderTpl-and-display-actual-grid-column-title

This solution overrides the Ext.grid.feature.Grouping to also return the title of the group and its rendered value.

zlevardy
27 Aug 2012, 8:04 AM
i was not able to use inline methods with INPUT element:




items: { xtype: 'grid', selModel: Ext.create('Ext.selection.RowModel', { listeners: { select: {fn: me.rowSelect, scope: me } } }), features: [ Ext.create('Ext.grid.feature.Grouping',{ groupHeaderTpl: Ext.create('Ext.XTemplate',' {[this.groupSelect()]}: <input type="button" onclick="this.groupSelect" value="select"> {name} ', { groupSelect: function(value) { console.log('tpl grp sel: '+value); } } ), startCollapsed: false, enableGroupingMenu: false, collapsible: false })], columns: [ ... ] ...

Button this.groupSelect not fired. The section before colon simply executed fine.

any hints?

Thx