Skip to content

Commit 8ad4dfa

Browse files
committed
Enh(grouping) Support for column footer in treeBase
Check for the `showColumnFooter` grid option in tree base, if present without a aggregationType, use the treeAggregationFn. Fix several incorrect documentation references in treeBase Closes #3822
1 parent 8f0cf4c commit 8ad4dfa

File tree

2 files changed

+63
-22
lines changed

2 files changed

+63
-22
lines changed

misc/tutorial/320_complex_grouping.ngdoc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ children of the selected rowHeader.
4242
enableFiltering: true,
4343
enableGroupHeaderSelection: true,
4444
treeRowHeaderAlwaysVisible: false,
45+
showColumnFooter: true,
4546
treeCustomAggregations: {
4647
variance: {label: 'var: ', menuTitle: 'Agg: Var', aggregationFn: stats.aggregator.sumSquareErr, finalizerFn: stats.finalizer.variance },
4748
stdev: {label: 'stDev: ', aggregationFn: stats.aggregator.sumSquareErr, finalizerFn: stats.finalizer.stDev},
@@ -60,22 +61,22 @@ children of the selected rowHeader.
6061
{ field: 'age', displayName: 'Age (common)', customTreeAggregationFn: stats.aggregator.mode, width: '10%' },
6162
{ name: 'company', width: '15%' },
6263
{ name: 'state', grouping: { groupPriority: 0 }, sort: { priority: 0, direction: 'desc' }, width: '25%', 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>' },
63-
{ field: 'balance', displayName: 'balance (avg)', width: '15%', cellFilter: 'currency',
64+
{ field: 'balance', displayName: 'balance (avg)', width: '15%', cellFilter: 'currency', footerCellFilter: 'currency',
6465
treeAggregationType: uiGridGroupingConstants.aggregation.AVG,
6566
customTreeAggregationFinalizerFn: function( aggregation ) {
6667
aggregation.rendered = aggregation.value;
6768
}
6869
},
69-
{ field: 'balance', displayName: 'balance (total)', width: '15%', cellFilter: 'currency',
70+
{ field: 'balance', displayName: 'balance (total)', width: '15%', cellFilter: 'currency', footerCellFilter: 'currency',
7071
treeAggregationType: uiGridGroupingConstants.aggregation.SUM,
7172
customTreeAggregationFinalizerFn: function( aggregation ) {
7273
aggregation.rendered = aggregation.value;
7374
}
7475
},
75-
{ field: 'balance', displayName: 'balance (median)', width: '15%', cellFilter: 'currency',
76+
{ field: 'balance', displayName: 'balance (median)', width: '15%', cellFilter: 'currency', footerCellFilter: 'currency',
7677
treeAggregationType: 'median',
7778
},
78-
{ field: 'balance', displayName: 'balance (std dev)', width: '15%', cellFilter: 'currency',
79+
{ field: 'balance', displayName: 'balance (std dev)', width: '15%', cellFilter: 'currency', footerCellFilter: 'currency',
7980
treeAggregationType: 'stdev',
8081
}
8182
],

src/features/tree-base/js/tree-base.js

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858
* will turn on any sorts that haven't run. It will then call a recursive sort on the tree.
5959
*
6060
* Tree base provides treeAggregation. It checks the treeAggregation configuration on each column, and aggregates based on
61-
* the logic provided as it builds the tree. Aggregation information will be collected in the format:
61+
* the logic provided as it builds the tree. Footer aggregation from the uiGrid core should not be used with treeBase aggregation,
62+
* since it operates on all visible rows, as opposed to to leaf nodes only. Setting `showColumnFooter: true` will show the
63+
* treeAggregations in the column footer. Aggregation information will be collected in the format:
6264
*
6365
* ```
6466
* {
@@ -70,7 +72,7 @@
7072
* ```
7173
*
7274
* A callback is provided to format the value once it is finalised (aka a valueFilter).
73-
*
75+
*
7476
* <br/>
7577
* <br/>
7678
*
@@ -1299,6 +1301,12 @@
12991301
grid.columns.forEach( function(column){
13001302
if ( typeof(column.treeAggregationFn) !== 'undefined' ){
13011303
aggregateArray.push( service.buildAggregationObject(column) );
1304+
1305+
if ( grid.options.showColumnFooter && typeof(column.colDef.aggregationType) === 'undefined' && column.treeAggregation ){
1306+
// Add aggregation object for footer
1307+
column.treeFooterAggregation = service.buildAggregationObject(column);
1308+
column.aggregationType = service.treeFooterAggregationType;
1309+
}
13021310
}
13031311
});
13041312
return aggregateArray;
@@ -1308,7 +1316,7 @@
13081316
/**
13091317
* @ngdoc function
13101318
* @name aggregate
1311-
* @methodOf ui.grid.grouping.service:uiGridGroupingService
1319+
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
13121320
* @description Accumulate the data from this row onto the aggregations for each parent
13131321
*
13141322
* Iterate over the parents, then iterate over the aggregations for each of those parents,
@@ -1323,12 +1331,16 @@
13231331
return;
13241332
}
13251333

1326-
parents.forEach( function( parent ){
1334+
parents.forEach( function( parent, index ){
13271335
if ( parent.treeNode.aggregations ){
13281336
parent.treeNode.aggregations.forEach( function( aggregation ){
13291337
var fieldValue = grid.getCellValue(row, aggregation.col);
13301338
var numValue = Number(fieldValue);
13311339
aggregation.col.treeAggregationFn(aggregation, fieldValue, numValue, row);
1340+
1341+
if ( index === 0 && typeof aggregation.col.treeFooterAggregation !== 'undefined' ){
1342+
aggregation.col.treeAggregationFn(aggregation.col.treeFooterAggregation, fieldValue, numValue, row);
1343+
}
13321344
});
13331345
}
13341346
});
@@ -1419,10 +1431,35 @@
14191431
return nativeAggregations;
14201432
},
14211433

1434+
/**
1435+
* @ngdoc function
1436+
* @name finaliseAggregation
1437+
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
1438+
* @description Helper function used to finalize aggregation nodes and footer cells
1439+
*
1440+
* @param {gridRow} row the parent we're finalising
1441+
* @param {aggregation} the aggregation object manipulated by the aggregationFn
1442+
*/
1443+
finaliseAggregation: function(row, aggregation){
1444+
if ( aggregation.col.treeAggregationUpdateEntity && typeof(row) !== 'undefined' && typeof(row.entity[ '$$' + aggregation.col.uid ]) !== 'undefined' ){
1445+
angular.extend( aggregation, row.entity[ '$$' + aggregation.col.uid ]);
1446+
}
1447+
1448+
if ( typeof(aggregation.col.treeAggregationFinalizerFn) === 'function' ){
1449+
aggregation.col.treeAggregationFinalizerFn( aggregation );
1450+
}
1451+
if ( typeof(aggregation.col.customTreeAggregationFinalizerFn) === 'function' ){
1452+
aggregation.col.customTreeAggregationFinalizerFn( aggregation );
1453+
}
1454+
if ( typeof(aggregation.rendered) === 'undefined' ){
1455+
aggregation.rendered = aggregation.label ? aggregation.label + aggregation.value : aggregation.value;
1456+
}
1457+
},
1458+
14221459
/**
14231460
* @ngdoc function
14241461
* @name finaliseAggregations
1425-
* @methodOf ui.grid.grouping.service:uiGridGroupingService
1462+
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
14261463
* @description Format the data from the aggregation into the rendered text
14271464
* e.g. if we had label: 'sum: ' and value: 25, we'd create 'sum: 25'.
14281465
*
@@ -1443,19 +1480,7 @@
14431480
}
14441481

14451482
row.treeNode.aggregations.forEach( function( aggregation ) {
1446-
if ( aggregation.col.treeAggregationUpdateEntity && typeof(row.entity[ '$$' + aggregation.col.uid ]) !== 'undefined' ){
1447-
angular.extend( aggregation, row.entity[ '$$' + aggregation.col.uid ]);
1448-
}
1449-
1450-
if ( typeof(aggregation.col.treeAggregationFinalizerFn) === 'function' ){
1451-
aggregation.col.treeAggregationFinalizerFn( aggregation );
1452-
}
1453-
if ( typeof(aggregation.col.customTreeAggregationFinalizerFn) === 'function' ){
1454-
aggregation.col.customTreeAggregationFinalizerFn( aggregation );
1455-
}
1456-
if ( typeof(aggregation.rendered) === 'undefined' ){
1457-
aggregation.rendered = aggregation.label ? aggregation.label + aggregation.value : aggregation.value;
1458-
}
1483+
service.finaliseAggregation(row, aggregation);
14591484

14601485
if ( aggregation.col.treeAggregationUpdateEntity ){
14611486
var aggregationCopy = {};
@@ -1468,6 +1493,21 @@
14681493
row.entity[ '$$' + aggregation.col.uid ] = aggregationCopy;
14691494
}
14701495
});
1496+
},
1497+
1498+
/**
1499+
* @ngdoc function
1500+
* @name treeFooterAggregationType
1501+
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
1502+
* @description Uses the tree aggregation functions and finalizers to set the
1503+
* column footer aggregations.
1504+
*
1505+
* @param {rows} visible rows. not used, but accepted to match signature of GridColumn.aggregationType
1506+
* @param {gridColumn} the column we are finalizing
1507+
*/
1508+
treeFooterAggregationType: function( rows, column ) {
1509+
service.finaliseAggregation(undefined, column.treeFooterAggregation);
1510+
return column.treeFooterAggregation.rendered;
14711511
}
14721512
};
14731513

0 commit comments

Comments
 (0)