问题
I am currently implementing ag-grid in my angular 7 application. I need to include the footer for each group which I have achieved. I would now need to display the Total of EMV(USD) and Percent Column like the screenshot below. The row should be blank for each cell except for the two columns mentioned and the totals should be displayed
Component
import { Component, Injectable, NgZone, ViewEncapsulation, ViewChild, Input } from '@angular/core';
import { OnInit } from '@angular/core';
import { AllocationsService } from '../services/allocations.service';
import { formatDate } from '@angular/common';
import { GridOptions } from 'ag-grid-community/dist/lib/entities/gridOptions';
import { Comparator } from '../utilities/comparator';
import { ActivatedRoute } from '@angular/router';
import { TestBed } from '@angular/core/testing';
@Component({
selector: 'mgr-allocations',
templateUrl: './allocations.component.html'
})
export class AllocationsComponent implements OnInit {
private Error: string;
public evalDate: Date;
private _evalDate: Date;
public AllocationDetails: any;
private _ManagerStrategyId: number;
public GridOptions: GridOptions;
windowHeight: any;
offset: number;
ngZone: any;
router: any;
Comparator: Comparator;
Route: any;
public get ManagerStrategyId(): number {
return this._ManagerStrategyId;
}
@Input()
public set ManagerStrategyId(value: number) {
this._ManagerStrategyId = value;
}
constructor(private allocationsService: AllocationsService, private comparator: Comparator,
private zone: NgZone, private route: ActivatedRoute) {
this.Comparator = comparator;
this.Route = route;
window.onresize = (e) => {
this.ngZone.run(() => {
this.windowHeight = window.innerHeight - this.offset;
setTimeout(() => {
if (!this.GridOptions || !this.GridOptions.api) {
return;
}
this.GridOptions.api.sizeColumnsToFit();
}, 500, true);
});
};
}
private FormattedDate(dateToFormat: Date): string {
return formatDate(dateToFormat, 'yyyy/MM/dd', 'en');
}
get MissingProductKeys() {
const missingProductsTypesNames = this.AllocationDetails.MissingProducts.flat().map(({ProductType}) => ProductType);
const uniqueProductTypeNames = new Set(missingProductsTypesNames);
return Array.from(uniqueProductTypeNames.values());
}
setGridOptions() {
this.GridOptions = {
columnDefs: this.getColumns(),
enableFilter: true,
treeData: true,
enableColResize: true,
animateRows: true,
groupDefaultExpanded: 1,
enableSorting: true,
suppressCellSelection: true,
groupIncludeFooter: true,
getDataPath: function (data) {
return data.Hierarchy;
},
onGridReady: e => {
if (!e || !e.api) {
return;
}
e.api.sizeColumnsToFit();
this.setDefaultSortOrder();
},
getRowStyle: (params) => {
if (params.node.level === 0) {
return { 'background-color': '#FCE7D7' };
}
},
autoGroupColumnDef: {
headerName: 'Manager Strategy', width: 300,
valueFormatter: uniqueColumn
},
};
function uniqueColumn(params) {
const startIndex = params.value.indexOf('#');
if (startIndex === -1) { return params.value; }
const endIndex = params.value.length;
return params.value.replace(params.value.substring(startIndex, endIndex), '');
}
}
ngOnInit() {
this.evalDate = new Date();
this.setGridOptions();
this.getAllocationsDetails(this.FormattedDate(this.evalDate));
}
getAllocationsDetails(evalDate: string) {
if (this.ManagerStrategyId != null) {
this.initGrid();
//this.GridOptions.api.showLoadingOverlay();
this.allocationsService.getAllocationsDetails(this.ManagerStrategyId, evalDate)
.subscribe(data => {
this.AllocationDetails = data;
this.GridOptions.rowData = this.AllocationDetails.ManagerAllocations;
setTimeout(() => {
// this.GridOptions.api.hideOverlay();
}, 100, true);
},
err => {
this.Error = 'An error has occurred. Please contact BSG';
},
() => {
// this.GridOptions.api.hideOverlay();
});
}
}
public evalDateChanged(value: Date): void {
this.getAllocationsDetails(this.FormattedDate((value)));
}
GridHeight() {
if (!this.windowHeight) {
this.windowHeight = window.innerHeight - this.offset + 10;
}
return this.windowHeight;
}
setDefaultSortOrder() {
const defaultSortModel = [
{ colId: 'ManagerStrategyName', sort: 'asc' },
{ colId: 'ManagerFundName', sort: 'asc' }
];
this.GridOptions.api.setSortModel(defaultSortModel);
}
private initGrid() {
const self = this;
}
private getColumns(): Array<any> {
const self = this;
const definition = [
{ headerName: 'Date', field: 'EvalDate', hide: true },
{ headerName: 'Firm ID', field: 'FirmID', hide: true },
{ headerName: 'Manager Strategy ID', field: 'FirmName', hide: true },
{ headerName: 'Firm', field: 'ManagerStrategyID', hide: true },
{ headerName: 'Manager Strategy', field: 'ManagerStrategyName' , hide: false },
{ headerName: 'Fund ID', field: 'ManagerFundID', hide: true },
{ headerName: 'Fund', field: 'ManagerFundName' },
{ headerName: 'Portfolio', field: 'ProductName' },
{ headerName: 'As Of', field: 'EvalDate', cellRenderer: (data) => {
return data.value ? (new Date(data.value)).toLocaleDateString() : '';
} },
{ headerName: 'EMV (USD)', field: 'UsdEmv', valueFormatter: currencyFormatter },
{ headerName: 'Percent', field: 'GroupPercent', valueFormatter: formatPercent },
];
function currencyFormatter(params) {
if (!isNaN(params.value)) {
return '$' + formatNumber(params.value);
}
}
function formatNumber(number) {
// this puts commas into the number eg 1000 goes to 1,000,
return Math.floor(number).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
}
function formatPercent(number) {
if (!isNaN(number.value)) {
return (number.value * 100).toFixed(2) + '%';
}
}
return definition;
}
}
New code based on proposed answer
private getColumns(): Array<any> {
const self = this;
const definition = [
{ headerName: 'Date', field: 'EvalDate', hide: true },
{ headerName: 'Firm ID', field: 'FirmID', hide: true },
{ headerName: 'Manager Strategy ID', field: 'FirmName', hide: true },
{ headerName: 'Firm', field: 'ManagerStrategyID', hide: true },
{ headerName: 'Manager Strategy', field: 'ManagerStrategyName', hide: false },
{ headerName: 'Fund ID', field: 'ManagerFundID', hide: true },
{ headerName: 'Fund', field: 'ManagerFundName' },
{ headerName: 'Portfolio', field: 'ProductName' },
{
headerName: 'As Of', field: 'EvalDate', cellRenderer: (data) => {
return data.value ? (new Date(data.value)).toLocaleDateString() : '';
}
},
{
headerName: 'EMV (USD)', field: 'UsdEmv', valueFormatter: this.currencyFormatter,
cellRenderer: 'agGroupCellRenderer',
aggFunc: 'sum',
cellRendererParams: {
footerValueGetter: (params) => params.value
}
},
{
headerName: 'Percent', field: 'GroupPercent', valueFormatter: this.formatPercent,
cellRenderer: 'agGroupCellRenderer',
aggFunc: 'sum',
cellRendererParams: {
footerValueGetter: (params) => params.value
}
}
];
return definition;
}
currencyFormatter(number) {
// this puts commas into the number eg 1000 goes to 1,000,
if (!isNaN(number.value)) {
number = Math.floor(number.value).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
number = number === '0' ? '0.00' : number;
return '$' + number;
}
}
formatPercent(number) {
if (!isNaN(number.value)) {
return (number.value * 100).toFixed(2) + '%';
}
}
New Screenshot
回答1:
I've made it in a different way:
let pinnedBottomData = this.generatePinnedBottomData();
this.gridApi.setPinnedBottomRowData([pinnedBottomData]);
generatePinnedBottomData(){
// generate a row-data with null values
let result = {};
this.gridColumnApi.getAllGridColumns().forEach(item => {
result[item.colId] = null;
});
return this.calculatePinnedBottomData(result);
}
calculatePinnedBottomData(target:any){
//list of columns for aggregation
let columnsWithAggregation = ['age']
columnsWithAggregation.forEach(element => {
this.gridApi.forEachNodeAfterFilter((rowNode: RowNode) => {
if (rowNode.data[element])
target[element] += Number(rowNode.data[element].toFixed(2));
});
if (target[element])
target[element] = `Age Sum: ${target[element].toFixed(2)}`;
})
return target;
}
Demo
回答2:
I have found this earlier on, whereby you can make use of aligned grids as footer. They have included an example, so you should refer to it.
A summary, on the component.html, you have to include the ag-grid-angular
component twice on your template, each of them with its own individual gridOptions
properties
<ag-grid-angular #topGrid [gridOptions]="topOptions"></ag-grid-angular>
<ag-grid-angular #bottomGrid [gridOptions]="bottomOptions".... ></ag-grid-angular>
And on your component.ts, you will define your columnDefs
as usual, as well as the respective gridOptions
.
As mentioned on the example on the link above, aligning the two grids will give you a footer grid which is vertically aligned to your main grid. This way, you can display the total value, etc on that footer.
回答3:
For each column definition, you can pass an extra parameter to change how the column is rendered
cellRenderer:'agGroupCellRenderer',
cellRendererParams: {
footerValueGetter: (params) => 'Text (' + params.value + ')'
},
aggFunc: "sum"
where params.value is the column name
来源:https://stackoverflow.com/questions/55009358/need-to-display-total-values-in-the-footer-in-ag-grid-using-angular