There is no row at the group top level because there could be many child rows grouped under one group. So row.entity is actually an object with group level values. You can traverse the groups children and then use one of them to render the group header.
You can try something along this lines,
$scope.gridOptions = {
//enableFiltering: true,
treeRowHeaderAlwaysVisible: false,
columnDefs: [
{ name: 'name', width: '30%' },
{ name: 'gender', grouping: { groupPriority: 1 }, sort: { priority: 1, direction: 'asc' }, width: '20%', cellFilter: 'mapGender' },
{ name: 'age', treeAggregationType: uiGridGroupingConstants.aggregation.MAX, width: '20%' },
{ name: 'company', width: '25%' },
{ name: 'registered', width: '40%', cellFilter: 'date', type: 'date' },
{ name: 'zip', displayName:'State' ,grouping: { groupPriority: 0 }, sort: { priority: 0, direction: 'desc' }, width: '35%', cellTemplate: '<span>{{grid.appScope.name(grid, row)}}</span>' },
//the below commented is the actual col but I did grouping with zip and put state of that zip
//{ name: 'state', grouping: { groupPriority: 0 }, sort: { priority: 0, direction: 'desc' }, width: '35%', cellTemplate: '<div><div ng-if="!col.grouping || col.grouping.groupPriority === undefined || col.grouping.groupPriority === null || ( row.groupHeader && col.grouping.groupPriority === row.treeLevel )" class="ui-grid-cell-contents" title="TOOLTIP">{{COL_FIELD CUSTOM_FILTERS}}</div></div>' },
],
};
$scope.name = function(grid,row,col)
{
console.log(row);
if(row.groupHeader && row.treeNode.children[0].row.treeNode.children[0])
{
var entity = row.treeNode.children[0].row.treeNode.children[0].row.entity;
return entity.state;
}
else if(row.treeNode.children[0])
{
var entity = row.treeNode.children[0].row.entity;
return entity.state;
}
return row.entity.state;
}
http://plnkr.co/edit/jimngRJ1rKmEIKhtpruU?p=preview