This Knowledge base explains how to show the calculated value of children only in parent row without using Aggregates in Tree Grid. Solution In Tree Grid, we need to use Aggregates functionality to calculate and display aggregate value of records. It will be shown in the footer template of Tree Grid by default. We can also display calculated value of children in parent row with the help of valueAccessor property of columns without using Aggregates. Customization The valueAccessor is used to access/manipulate the value of display data. You can achieve custom value formatting by using valueAccessor. For showing the calculated value of child records in parent row, we need to check whether the current record has children by using the property “hasChildRecords”. If it has children, we need to manipulate those children’s value and return the final calculated value. Then set it as parent’s value. JS import { TreeGrid } from "@syncfusion/ej2-treegrid"; import { summaryRowData } from "./data-source"; import { isNullOrUndefined } from "@syncfusion/ej2-base"; let treegrid: TreeGrid = new TreeGrid({ dataSource: summaryRowData, childMapping: "children", treeColumnIndex: 0, height: 400, columns: [ { field: "FreightID", headerText: "Freight ID", width: 130 }, { field: "FreightName", width: 195, headerText: "Freight Name" }, { field: "UnitWeight", headerText: "Customized Weight Per Unit using value accessor", type: "number", valueAccessor: totalChildValue, clipMode: "EllipsisWithTooltip", width: 130, textAlign: "Right" }, { field: "TotalUnits", headerText: "Total Units", type: "number", width: 125, textAlign: "Right" } ] }); treegrid.appendTo("#TreeGrid"); function totalChildValue(field, data, column) { if (!isNullOrUndefined(data.hasChildRecords)) { //checking if the record has children let totalUnitWeight = 0; data.children.map(row => (totalUnitWeight += row["UnitWeight"])); return totalUnitWeight; } return data.UnitWeight; } Figure 1 show calculated child value in parent record JavaScriptDemo Also refer the other frameworks demo links below, AngularDemo ReactDemo VueDemo
Usually, remote data handlers like WebAPIAdaptor, return only the current page records which is the default behavior. So, we can summarize the current page records only in the Grid Summary Footer. The concept behind this adaptor brings the records on demand which means client-end receives only the current page records. Based on the received records only this adaptor summarizes the aggregates and displays them in Grid. If we return whole records to the client-end, concept of the load on demand will be declined. Henceforth, based on the current page records the summary were displayed. However, we can overcome this behavior using the custom adaptors and custom headers of the DataManager. Using the custom headers, required aggregate fields were shared to the server-end. Based on that selective fields with their records were returned to the client as aggregates along with the Items/count which will display the summary for total records. HTML: <div id="Grid"></div> JavaScript: <script type="text/javascript"> $(function () { $("#Grid").ejGrid({ dataSource: new ej.DataManager({ url: "/api/Orders", adaptor: new ej.WebApiAdaptor() }), allowPaging: true, showSummary: true, summaryRows: [ { title: "Sum", summaryColumns: [ { summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" } ] } ], load: "onLoad", actionBegin: "onActionBegin", columns: [ { field: "OrderID", headerText: "Order ID", textAlign: ej.TextAlign.Right }, { field: "CustomerID", headerText: "Customer ID" }, { field: "EmployeeID", headerText: "Employee ID", textAlign: ej.TextAlign.Right }, { field: "Freight", format: "{0:C3}", textAlign: ej.TextAlign.Right }, { field: "ShipCity", headerText: "Ship City" } ] }); }); </script> Razor: @(Html.EJ().Grid<object>("Grid") .AllowPaging() .Datasource(ds => { ds.URL("/api/Orders"); ds.Adaptor(AdaptorType.WebApiAdaptor); }) .ShowSummary() .SummaryRow(row => { row.Title("Sum") .SummaryColumns(col => { col.SummaryType(SummaryType.Sum) .Format("{0:C3}") .DisplayColumn("Freight") .DataMember("Freight").Add(); }).Add(); }) .ClientSideEvents(events => { events.ActionBegin("onActionBegin"); events.Load("onLoad"); }) .Columns(col => { col.Field("OrderID").HeaderText("Order ID").TextAlign(TextAlign.Right).Add(); col.Field("CustomerID").HeaderText("Customer ID").Add(); col.Field("EmployeeID").HeaderText("EmployeeID").TextAlign(TextAlign.Right).Add(); col.Field("Freight").Format("{0:C3}").TextAlign(TextAlign.Right).Add(); col.Field("ShipCity").HeaderText("Ship City").Add(); }) ) WebForms: <ej:Grid id="Grid" runat="server" ShowSummary="true" Allowpaging="true"> <EditSettings AllowEditing="True" AllowAdding="True" AllowDeleting="True" EditMode="Batch"></EditSettings> <ToolbarSettings ShowToolbar="True" ToolbarItems="add,edit,delete,update,cancel"></ToolbarSettings> <Columns> <ej:Column Field="OrderID" HeaderText="Order ID" IsPrimaryKey="true" TextAlign="Right" /> <ej:Column Field="CustomerID" HeaderText="Customer ID" /> <ej:Column Field="EmployeeID" HeaderText="Employee ID" TextAlign="Right" /> <ej:Column Field="Freight" Format ="{0:C3}" TextAlign="Right"/> <ej:Column Field="ShipCity" HeaderText="Ship City"/> </Columns> <SummaryRows> <ej:SummaryRow Title="Sum"> <SummaryColumn> <ej:SummaryColumn SummaryType="Sum" Format="{0:C3}" DisplayColumn="Freight" DataMember="Freight" /> </SummaryColumn> </ej:SummaryRow> </SummaryRows> <ClientSideEvents Load="onLoad" ActionBegin="onActionBegin" /> </ej:Grid> .Net Core <ej-grid id="Grid" allow-paging="true" load="onLoad" show-summary="true" action-begin="onActionBegin"> <e-datamanager url="/api/Orders" adaptor="WebApiAdaptor" /> <e-summary-rows> <e-summary-row title="Sum"> <e-summary-columns> <e-summary-column summary-type="Sum" format="{0:C3}" display-column="Freight" datamember="Freight" /> </e-summary-columns> </e-summary-row> </e-summary-rows> <e-columns> <e-column field="OrderID" header-text="Order ID" is-primary-key="true" text-align="Right"></e-column> <e-column field="EmployeeID" header-text="Employee ID" text-align="Right"></e-column> <e-column field="CustomerID" header-text="Customer ID"></e-column> <e-column field="Freight" text-align="Right" format="{0:C3}"></e-column> <e-column field="ShipCity" header-text="Ship City"> </e-column> </e-columns> </ej-grid> Angular2: <ej-grid id="Grid" #grid [allowPaging]="true" [showSummary]="true" [summaryRows]="summaryrows" [dataSource]="datasrc" (load)="onLoad($event)" (actionBegin)="onActionBegin($event)"> <e-columns> <e-column field="OrderID" headerText="Order ID" isPrimaryKey="true" textAlign="right"></e-column> <e-column field="CustomerID" headerText="Customer ID"></e-column> <e-column field="EmployeeID" headerText="Employee Name" textAlign="right"></e-column> <e-column field="Freight" format="{0:C3}" textAlign="right"></e-column> <e-column field="ShipCity" headerText="Ship City"></e-column> </e-columns> </ej-grid> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.datasrc = new ej.DataManager({ url: "/api/Values", adaptor: new ej.WebApiAdaptor() }) this.summaryrows = [{ title: "Sum", summaryColumns: [{ summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" }] }] } public datasrc: any; public summaryrows: any; } Define the Load and ActionBegin events of the Grid along with the customAdaptor. In the Load event, assign the newly extended adaptor to the Grid’s dataSource. In the ActionBegin event, lookup the model.query for aggregates and push them to the custom headers of the dataSource, an ej.DataManager instance. <script> var customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData;; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej.aggregates[agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); function onLoad(args) { this.model.dataSource.adaptor = new customAdaptor(); } function onActionBegin(args) { var rows = this.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } this.model.dataSource.dataSource.headers = []; this.model.dataSource.dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } </script> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej["aggregates"][agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); } public customAdaptor: any; onLoad(args) { args.model.dataSource().adaptor = new this.customAdaptor; } onActionBegin(args) { var rows = args.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } args.model.dataSource().dataSource.headers = []; args.model.dataSource().dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } } In the server-end, retrieve the pushed aggregated values and deserialize them to List<string>. Use the deserialized object as input for DataOperations for selecting the aggregate columns. Later, return them to the client-end along with the Items/Count wrapped object. Web API Controller: public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { var queryString = HttpContext.Current.Request.QueryString; string agg = Request.Headers.GetValues("aggregates").ToList()[0]; int skip = Convert.ToInt32(queryString["$skip"]); int take = Convert.ToInt32(queryString["$top"]); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Asp.Net core WebApi controller public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { string agg = Request.Headers["aggregates"].ToString(); int skip = Convert.ToInt32(Request.Query.ToList()[1].Value.ToString()); int take = Convert.ToInt32(Request.Query.ToList()[2].Value.ToString()); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); List<string> str = new List<string>(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Note: To avoid the serialization error only, WebApiAdaptor is prevented the default aggregate records returning from server-end. But this KB, proposed a way to generate aggregate for total records. It may lead to the serialization error in the case larger record count. Figure. Grid with summation of total records for Freight Column.ConclusionI hope you enjoyed learning about how to get aggregate WebApiAdaptor enabled in ASP.NET MVC Grid.You can refer to our ASP.NET MVC Grid feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications. You can also explore our ASP.NET MVC Grid example to understand how to create and manipulate data.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
Usually, remote data handlers like WebAPIAdaptor, return only the current page records which is the default behavior. So, we can summarize the current page records only in the Grid Summary Footer. The concept behind this adaptor brings the records on demand which means client-end receives only the current page records. Based on the received records only this adaptor summarizes the aggregates and displays them in Grid. If we return whole records to the client-end, concept of the load on demand will be declined. Henceforth, based on the current page records the summary were displayed. However, we can overcome this behavior using the custom adaptors and custom headers of the DataManager. Using the custom headers, required aggregate fields were shared to the server-end. Based on that selective fields with their records were returned to the client as aggregates along with the Items/count which will display the summary for total records. HTML: <div id="Grid"></div> JavaScript: <script type="text/javascript"> $(function () { $("#Grid").ejGrid({ dataSource: new ej.DataManager({ url: "/api/Orders", adaptor: new ej.WebApiAdaptor() }), allowPaging: true, showSummary: true, summaryRows: [ { title: "Sum", summaryColumns: [ { summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" } ] } ], load: "onLoad", actionBegin: "onActionBegin", columns: [ { field: "OrderID", headerText: "Order ID", textAlign: ej.TextAlign.Right }, { field: "CustomerID", headerText: "Customer ID" }, { field: "EmployeeID", headerText: "Employee ID", textAlign: ej.TextAlign.Right }, { field: "Freight", format: "{0:C3}", textAlign: ej.TextAlign.Right }, { field: "ShipCity", headerText: "Ship City" } ] }); }); </script> Razor: @(Html.EJ().Grid<object>("Grid") .AllowPaging() .Datasource(ds => { ds.URL("/api/Orders"); ds.Adaptor(AdaptorType.WebApiAdaptor); }) .ShowSummary() .SummaryRow(row => { row.Title("Sum") .SummaryColumns(col => { col.SummaryType(SummaryType.Sum) .Format("{0:C3}") .DisplayColumn("Freight") .DataMember("Freight").Add(); }).Add(); }) .ClientSideEvents(events => { events.ActionBegin("onActionBegin"); events.Load("onLoad"); }) .Columns(col => { col.Field("OrderID").HeaderText("Order ID").TextAlign(TextAlign.Right).Add(); col.Field("CustomerID").HeaderText("Customer ID").Add(); col.Field("EmployeeID").HeaderText("EmployeeID").TextAlign(TextAlign.Right).Add(); col.Field("Freight").Format("{0:C3}").TextAlign(TextAlign.Right).Add(); col.Field("ShipCity").HeaderText("Ship City").Add(); }) ) WebForms: <ej:Grid id="Grid" runat="server" ShowSummary="true" Allowpaging="true"> <EditSettings AllowEditing="True" AllowAdding="True" AllowDeleting="True" EditMode="Batch"></EditSettings> <ToolbarSettings ShowToolbar="True" ToolbarItems="add,edit,delete,update,cancel"></ToolbarSettings> <Columns> <ej:Column Field="OrderID" HeaderText="Order ID" IsPrimaryKey="true" TextAlign="Right" /> <ej:Column Field="CustomerID" HeaderText="Customer ID" /> <ej:Column Field="EmployeeID" HeaderText="Employee ID" TextAlign="Right" /> <ej:Column Field="Freight" Format ="{0:C3}" TextAlign="Right"/> <ej:Column Field="ShipCity" HeaderText="Ship City"/> </Columns> <SummaryRows> <ej:SummaryRow Title="Sum"> <SummaryColumn> <ej:SummaryColumn SummaryType="Sum" Format="{0:C3}" DisplayColumn="Freight" DataMember="Freight" /> </SummaryColumn> </ej:SummaryRow> </SummaryRows> <ClientSideEvents Load="onLoad" ActionBegin="onActionBegin" /> </ej:Grid> .Net Core <ej-grid id="Grid" allow-paging="true" load="onLoad" show-summary="true" action-begin="onActionBegin"> <e-datamanager url="/api/Orders" adaptor="WebApiAdaptor" /> <e-summary-rows> <e-summary-row title="Sum"> <e-summary-columns> <e-summary-column summary-type="Sum" format="{0:C3}" display-column="Freight" datamember="Freight" /> </e-summary-columns> </e-summary-row> </e-summary-rows> <e-columns> <e-column field="OrderID" header-text="Order ID" is-primary-key="true" text-align="Right"></e-column> <e-column field="EmployeeID" header-text="Employee ID" text-align="Right"></e-column> <e-column field="CustomerID" header-text="Customer ID"></e-column> <e-column field="Freight" text-align="Right" format="{0:C3}"></e-column> <e-column field="ShipCity" header-text="Ship City"> </e-column> </e-columns> </ej-grid> Angular2: <ej-grid id="Grid" #grid [allowPaging]="true" [showSummary]="true" [summaryRows]="summaryrows" [dataSource]="datasrc" (load)="onLoad($event)" (actionBegin)="onActionBegin($event)"> <e-columns> <e-column field="OrderID" headerText="Order ID" isPrimaryKey="true" textAlign="right"></e-column> <e-column field="CustomerID" headerText="Customer ID"></e-column> <e-column field="EmployeeID" headerText="Employee Name" textAlign="right"></e-column> <e-column field="Freight" format="{0:C3}" textAlign="right"></e-column> <e-column field="ShipCity" headerText="Ship City"></e-column> </e-columns> </ej-grid> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.datasrc = new ej.DataManager({ url: "/api/Values", adaptor: new ej.WebApiAdaptor() }) this.summaryrows = [{ title: "Sum", summaryColumns: [{ summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" }] }] } public datasrc: any; public summaryrows: any; } Define the Load and ActionBegin events of the Grid along with the customAdaptor. In the Load event, assign the newly extended adaptor to the Grid’s dataSource. In the ActionBegin event, lookup the model.query for aggregates and push them to the custom headers of the dataSource, an ej.DataManager instance. <script> var customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData;; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej.aggregates[agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); function onLoad(args) { this.model.dataSource.adaptor = new customAdaptor(); } function onActionBegin(args) { var rows = this.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } this.model.dataSource.dataSource.headers = []; this.model.dataSource.dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } </script> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej["aggregates"][agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); } public customAdaptor: any; onLoad(args) { args.model.dataSource().adaptor = new this.customAdaptor; } onActionBegin(args) { var rows = args.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } args.model.dataSource().dataSource.headers = []; args.model.dataSource().dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } } In the server-end, retrieve the pushed aggregated values and deserialize them to List<string>. Use the deserialized object as input for DataOperations for selecting the aggregate columns. Later, return them to the client-end along with the Items/Count wrapped object. Web API Controller: public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { var queryString = HttpContext.Current.Request.QueryString; string agg = Request.Headers.GetValues("aggregates").ToList()[0]; int skip = Convert.ToInt32(queryString["$skip"]); int take = Convert.ToInt32(queryString["$top"]); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Asp.Net core WebApi controller public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { string agg = Request.Headers["aggregates"].ToString(); int skip = Convert.ToInt32(Request.Query.ToList()[1].Value.ToString()); int take = Convert.ToInt32(Request.Query.ToList()[2].Value.ToString()); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); List<string> str = new List<string>(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Note: To avoid the serialization error only, WebApiAdaptor is prevented the default aggregate records returning from server-end. But this KB, proposed a way to generate aggregate for total records. It may lead to the serialization error in the case larger record count. Figure. Grid with summation of total records for Freight Column.Note:A new version of Essential Studio for ASP.NET is available. Versions prior to the release of Essential Studio 2014, Volume 2 will now be referred to as a classic versions.The new ASP.NET suite is powered by Essential Studio for JavaScript providing client-side rendering of HTML 5-JavaScript controls, offering better performance, and better support for touch interactivity. The new version includes all the features of the old version, so migration is easy.The Classic controls can be used in existing projects; however, if you are starting a new project, we recommend using the latest version of Essential Studio for ASP.NET. Although Syncfusion will continue to support all Classic Versions, we are happy to assist you in migrating to the newest edition.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls. If you have any queries or require clarifications, please let us know in the comments section below.You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
Usually, remote data handlers like WebAPIAdaptor, return only the current page records which is the default behavior. So, we can summarize the current page records only in the Grid Summary Footer. The concept behind this adaptor brings the records on demand which means client-end receives only the current page records. Based on the received records only this adaptor summarizes the aggregates and displays them in Grid. If we return whole records to the client-end, concept of the load on demand will be declined. Henceforth, based on the current page records the summary were displayed. However, we can overcome this behavior using the custom adaptors and custom headers of the DataManager. Using the custom headers, required aggregate fields were shared to the server-end. Based on that selective fields with their records were returned to the client as aggregates along with the Items/count which will display the summary for total records. HTML: <div id="Grid"></div> JavaScript: <script type="text/javascript"> $(function () { $("#Grid").ejGrid({ dataSource: new ej.DataManager({ url: "/api/Orders", adaptor: new ej.WebApiAdaptor() }), allowPaging: true, showSummary: true, summaryRows: [ { title: "Sum", summaryColumns: [ { summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" } ] } ], load: "onLoad", actionBegin: "onActionBegin", columns: [ { field: "OrderID", headerText: "Order ID", textAlign: ej.TextAlign.Right }, { field: "CustomerID", headerText: "Customer ID" }, { field: "EmployeeID", headerText: "Employee ID", textAlign: ej.TextAlign.Right }, { field: "Freight", format: "{0:C3}", textAlign: ej.TextAlign.Right }, { field: "ShipCity", headerText: "Ship City" } ] }); }); </script> Razor: @(Html.EJ().Grid<object>("Grid") .AllowPaging() .Datasource(ds => { ds.URL("/api/Orders"); ds.Adaptor(AdaptorType.WebApiAdaptor); }) .ShowSummary() .SummaryRow(row => { row.Title("Sum") .SummaryColumns(col => { col.SummaryType(SummaryType.Sum) .Format("{0:C3}") .DisplayColumn("Freight") .DataMember("Freight").Add(); }).Add(); }) .ClientSideEvents(events => { events.ActionBegin("onActionBegin"); events.Load("onLoad"); }) .Columns(col => { col.Field("OrderID").HeaderText("Order ID").TextAlign(TextAlign.Right).Add(); col.Field("CustomerID").HeaderText("Customer ID").Add(); col.Field("EmployeeID").HeaderText("EmployeeID").TextAlign(TextAlign.Right).Add(); col.Field("Freight").Format("{0:C3}").TextAlign(TextAlign.Right).Add(); col.Field("ShipCity").HeaderText("Ship City").Add(); }) ) WebForms: <ej:Grid id="Grid" runat="server" ShowSummary="true" Allowpaging="true"> <EditSettings AllowEditing="True" AllowAdding="True" AllowDeleting="True" EditMode="Batch"></EditSettings> <ToolbarSettings ShowToolbar="True" ToolbarItems="add,edit,delete,update,cancel"></ToolbarSettings> <Columns> <ej:Column Field="OrderID" HeaderText="Order ID" IsPrimaryKey="true" TextAlign="Right" /> <ej:Column Field="CustomerID" HeaderText="Customer ID" /> <ej:Column Field="EmployeeID" HeaderText="Employee ID" TextAlign="Right" /> <ej:Column Field="Freight" Format ="{0:C3}" TextAlign="Right"/> <ej:Column Field="ShipCity" HeaderText="Ship City"/> </Columns> <SummaryRows> <ej:SummaryRow Title="Sum"> <SummaryColumn> <ej:SummaryColumn SummaryType="Sum" Format="{0:C3}" DisplayColumn="Freight" DataMember="Freight" /> </SummaryColumn> </ej:SummaryRow> </SummaryRows> <ClientSideEvents Load="onLoad" ActionBegin="onActionBegin" /> </ej:Grid> .Net Core <ej-grid id="Grid" allow-paging="true" load="onLoad" show-summary="true" action-begin="onActionBegin"> <e-datamanager url="/api/Orders" adaptor="WebApiAdaptor" /> <e-summary-rows> <e-summary-row title="Sum"> <e-summary-columns> <e-summary-column summary-type="Sum" format="{0:C3}" display-column="Freight" datamember="Freight" /> </e-summary-columns> </e-summary-row> </e-summary-rows> <e-columns> <e-column field="OrderID" header-text="Order ID" is-primary-key="true" text-align="Right"></e-column> <e-column field="EmployeeID" header-text="Employee ID" text-align="Right"></e-column> <e-column field="CustomerID" header-text="Customer ID"></e-column> <e-column field="Freight" text-align="Right" format="{0:C3}"></e-column> <e-column field="ShipCity" header-text="Ship City"> </e-column> </e-columns> </ej-grid> Angular2: <ej-grid id="Grid" #grid [allowPaging]="true" [showSummary]="true" [summaryRows]="summaryrows" [dataSource]="datasrc" (load)="onLoad($event)" (actionBegin)="onActionBegin($event)"> <e-columns> <e-column field="OrderID" headerText="Order ID" isPrimaryKey="true" textAlign="right"></e-column> <e-column field="CustomerID" headerText="Customer ID"></e-column> <e-column field="EmployeeID" headerText="Employee Name" textAlign="right"></e-column> <e-column field="Freight" format="{0:C3}" textAlign="right"></e-column> <e-column field="ShipCity" headerText="Ship City"></e-column> </e-columns> </ej-grid> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.datasrc = new ej.DataManager({ url: "/api/Values", adaptor: new ej.WebApiAdaptor() }) this.summaryrows = [{ title: "Sum", summaryColumns: [{ summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" }] }] } public datasrc: any; public summaryrows: any; } Define the Load and ActionBegin events of the Grid along with the customAdaptor. In the Load event, assign the newly extended adaptor to the Grid’s dataSource. In the ActionBegin event, lookup the model.query for aggregates and push them to the custom headers of the dataSource, an ej.DataManager instance. <script> var customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData;; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej.aggregates[agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); function onLoad(args) { this.model.dataSource.adaptor = new customAdaptor(); } function onActionBegin(args) { var rows = this.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } this.model.dataSource.dataSource.headers = []; this.model.dataSource.dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } </script> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej["aggregates"][agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); } public customAdaptor: any; onLoad(args) { args.model.dataSource().adaptor = new this.customAdaptor; } onActionBegin(args) { var rows = args.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } args.model.dataSource().dataSource.headers = []; args.model.dataSource().dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } } In the server-end, retrieve the pushed aggregated values and deserialize them to List<string>. Use the deserialized object as input for DataOperations for selecting the aggregate columns. Later, return them to the client-end along with the Items/Count wrapped object. Web API Controller: public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { var queryString = HttpContext.Current.Request.QueryString; string agg = Request.Headers.GetValues("aggregates").ToList()[0]; int skip = Convert.ToInt32(queryString["$skip"]); int take = Convert.ToInt32(queryString["$top"]); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Asp.Net core WebApi controller public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { string agg = Request.Headers["aggregates"].ToString(); int skip = Convert.ToInt32(Request.Query.ToList()[1].Value.ToString()); int take = Convert.ToInt32(Request.Query.ToList()[2].Value.ToString()); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); List<string> str = new List<string>(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Note: To avoid the serialization error only, WebApiAdaptor is prevented the default aggregate records returning from server-end. But this KB, proposed a way to generate aggregate for total records. It may lead to the serialization error in the case larger record count. Figure. Grid with summation of total records for Freight Column. ConclusionI hope you enjoyed learning about how can I obtain a grid with aggregate WebApiAdaptor enabled?You can refer to our ASP.NET Core Grid feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications. You can also explore our ASP.NET Core Grid example to understand how to create and manipulate data.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!