Skip to content

SyncfusionExamples/custom-adaptor-with-pivot-table

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

6 Commits
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Syncfusionยฎ React Pivot Table โ€“ Custom Adaptor Quick Start

A production-ready quick start that connects the Syncfusionยฎ React Pivot Table to an ASP.NET Core OData backend using a Custom Adaptor built on top of ODataV4Adaptor โ€” enabling remote data binding with custom request/response processing and full CRUD operations.

React .NET Syncfusion License


๐Ÿ“‘ Table of Contents


๐Ÿš€ Quick Overview

This project demonstrates how to bind the Syncfusionยฎ React Pivot Table to a remote ASP.NET Core OData backend using a Custom Adaptor that extends ODataV4Adaptor. A Custom Adaptor is not a standalone adaptor โ€” it is a thin extension class that intercepts and customizes the data flow at three well-defined points (processQuery, beforeSend, processResponse) while reusing every other feature of the underlying base adaptor.

In this sample the CustomAdaptor class:

  1. Rewrites the API URL to point at the ASP.NET Core OData endpoint (http://localhost:5092/odata/Orders).
  2. Appends a custom query parameter (Syncfusion Grid=true) that the backend can read to identify requests originating from the Pivot Table.
  3. Injects an Authorization header on every outgoing request.
  4. Augments each record with a client-side SNo (serial number) field after the response is received.
Component Technology Purpose
๐ŸŽจ Frontend React 19 + Syncfusionยฎ EJ2 Render the interactive Pivot Table UI
โš™๏ธ Backend ASP.NET Core 10.0 + OData (NewtonsoftJson) Serve OData-formatted data, perform CRUD via OData conventions
๐Ÿ”Œ Adaptor CustomAdaptor extends ODataV4Adaptor Bridge between Pivot Table and OData service with custom hooks
๐Ÿ“Š Sample Data In-memory OrdersDetails list (seeded) Five seeded order records used for the Pivot Table

๐Ÿ’ก A Custom Adaptor is the right choice when the built-in adaptors are almost sufficient but you need to tweak a few specific behaviors โ€” for example adding auth headers, injecting custom query parameters, transforming responses, or attaching computed fields โ€” without rewriting an entire adaptor.


โœจ Key Features

  • ๐Ÿ“Š Remote Data Binding โ€“ Connects the Pivot Table to an ASP.NET Core OData endpoint over HTTP.
  • ๐Ÿงฉ Custom Adaptor Pattern โ€“ Extends ODataV4Adaptor and overrides processQuery, beforeSend, and processResponse.
  • ๐Ÿ”„ Full CRUD Support โ€“ Insert, update (PATCH), and delete records directly from the Pivot Table drill-through grid.
  • ๐Ÿ—‚๏ธ OData Query Support โ€“ $filter, $orderby, $top, $skip, $count are produced by the base adaptor and honored by the backend via [EnableQuery].
  • ๐Ÿ›ก๏ธ Property Casing Preservation โ€“ Uses DefaultContractResolver to keep PascalCase fields like OrderID, CustomerID.
  • ๐ŸŒ CORS-Enabled โ€“ Preconfigured to allow cross-origin requests from the React dev server.
  • โšก Drill-Through Editing โ€“ Double-click a pivot cell to add, edit, or delete underlying records in a pop-up grid.
  • ๐Ÿงฎ Client-Side Computed Fields โ€“ SNo is added to every record on the client via processResponse.
  • ๐Ÿ” Authentication Header Injection โ€“ Every request carries an Authorization header set inside beforeSend.
  • ๐Ÿ“ฆ Ready-to-Run โ€“ Clone, build, and start both projects โ€” no database setup required (in-memory sample data).

๐Ÿ› ๏ธ Prerequisites

Make sure the following software and packages are installed on your machine before running the project.

Software / Package Version Purpose
๐ŸŸข Node.js 18.x or later Runtime for the React development server
โš›๏ธ React 19.x Build the Pivot Table client
๐ŸŸฃ .NET SDK 10.0 or later Build and run the ASP.NET Core OData backend
๐Ÿง‘โ€๐Ÿ’ป Visual Studio / VS Code Latest Configure and run the backend service
๐Ÿ“ฆ @syncfusion/ej2-react-pivotview 33.1.45+ React Pivot Table component
๐Ÿ“ฆ @syncfusion/ej2-data 33.1.45+ DataManager, ODataV4Adaptor, and Query
๐Ÿ“ฆ @syncfusion/ej2-base 33.1.45+ setValue helper used inside processResponse
๐Ÿ“ฆ Microsoft.AspNetCore.OData 9.4.1+ OData endpoint support for ASP.NET Core
๐Ÿ“ฆ Microsoft.AspNetCore.Mvc.NewtonsoftJson 10.0.9+ Preserve original property casing during JSON serialization

๐Ÿ“‚ Project Structure

custom-adaptor-with-pivot-table/
โ”œโ”€โ”€ ๐Ÿ“ Client/                              # React frontend (Pivot Table)
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ public/
โ”‚   โ”‚   โ”œโ”€โ”€ index.html
โ”‚   โ”‚   โ”œโ”€โ”€ manifest.json
โ”‚   โ”‚   โ””โ”€โ”€ robots.txt
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ src/
โ”‚   โ”‚   โ”œโ”€โ”€ App.css                         # Component styles
โ”‚   โ”‚   โ”œโ”€โ”€ App.js                          # Pivot Table + CustomAdaptor class
โ”‚   โ”‚   โ”œโ”€โ”€ App.test.js
โ”‚   โ”‚   โ”œโ”€โ”€ datasource.js                   # Local fallback sample data
โ”‚   โ”‚   โ”œโ”€โ”€ index.css
โ”‚   โ”‚   โ”œโ”€โ”€ index.js                        # React entry point
โ”‚   โ”‚   โ”œโ”€โ”€ reportWebVitals.js
โ”‚   โ”‚   โ””โ”€โ”€ setupTests.js
โ”‚   โ””โ”€โ”€ package.json                        # React dependencies & scripts
โ”‚
โ”œโ”€โ”€ ๐Ÿ“ ODataV4Adaptor/                      # ASP.NET Core OData backend
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ Controllers/
โ”‚   โ”‚   โ””โ”€โ”€ OrdersController.cs             # OData endpoints: GET, GET(key), POST, PATCH, DELETE
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ Models/
โ”‚   โ”‚   โ””โ”€โ”€ OrdersDetails.cs                # Order data model + seeded sample data
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ Properties/
โ”‚   โ”‚   โ””โ”€โ”€ launchSettings.json             # Default port: 5092 (HTTP), 7181 (HTTPS)
โ”‚   โ”œโ”€โ”€ appsettings.Development.json
โ”‚   โ”œโ”€โ”€ appsettings.json
โ”‚   โ”œโ”€โ”€ ODataV4Adaptor.csproj               # Project file (net10.0)
โ”‚   โ”œโ”€โ”€ ODataV4Adaptor.http                 # Endpoint testing file
โ”‚   โ””โ”€โ”€ Program.cs                          # OData + Newtonsoft.Json + CORS configuration
โ”‚
โ”œโ”€โ”€ ๐Ÿ“„ README.md                            # You are here

๐Ÿง  Understanding the Custom Adaptor

A Custom Adaptor is a class that extends one of the built-in Syncfusionยฎ adaptors (UrlAdaptor, ODataV4Adaptor, WebApiAdaptor, GraphQLAdaptor) and overrides a small set of lifecycle methods. The base adaptor continues to handle the heavy lifting (building the request, parsing the response, applying paging, etc.), while your subclass adds the delta your application needs.

This sample extends ODataV4Adaptor and overrides three methods:

Method When it runs What it does in this sample
processQuery Before the HTTP request is built Rewrites requestContext.dataSource.url to http://localhost:5092/odata/Orders and calls query.addParams('Syncfusion Grid', 'true').
beforeSend Immediately before the request is sent to the server Sets the Authorization request header (sample value: true).
processResponse After the server response is received Iterates original.result and calls setValue('SNo', ++i, item) to attach a serial number.
// filepath: Client/src/App.js
import * as React from 'react';
import { PivotViewComponent } from '@syncfusion/ej2-react-pivotview';
import { DataManager, ODataV4Adaptor } from '@syncfusion/ej2-data';
import { setValue } from '@syncfusion/ej2-base';
import './App.css';

class CustomAdaptor extends ODataV4Adaptor {
    processQuery(dm, query) {
        dm.dataSource.url = 'http://localhost:5092/odata/Orders'; // Here xxxx represents the port number.
        query.addParams('Syncfusion Grid', 'true');               // Add the additional parameter.
        return super.processQuery.apply(this, arguments);
    }

    beforeSend(dm, request, settings) {
        request.headers.set('Authorization', `true`);
        super.beforeSend(dm, request, settings);
    }

    processResponse() {
        let i = 0;
        const original = super.processResponse.apply(this, arguments);
        // Adding serial number.
        if (original.result) {
            original.result.forEach((item) => setValue('SNo', ++i, item));
        }
        return original;
    }
}

๐Ÿ“ Because the base adaptor is ODataV4Adaptor, the request URL produced by Syncfusionยฎ uses OData v4 query syntax ($filter, $orderby, $top, $skip, $count) and the response is expected in the OData v4 shape: { "@odata.count": N, "value": [...] }. The backend is configured to honor exactly that contract.


โš™๏ธ Installation & Setup

1. Clone the Repository

git clone https://github.com/SyncfusionExamples/custom-adaptor-with-pivot-table.git
cd custom-adaptor-with-pivot-table

2. Backend โ€“ ASP.NET Core OData Service

The backend project lives in the ODataV4Adaptor/ folder.

2.1 Restore dependencies

cd ODataV4Adaptor
dotnet restore

2.2 Verify the required NuGet packages

ODataV4Adaptor.csproj references:

  • Microsoft.AspNetCore.OData โ€” OData routing and [EnableQuery] support.
  • Microsoft.AspNetCore.Mvc.NewtonsoftJson โ€” serializes properties using their original PascalCase names (OrderID, CustomerID, etc.) instead of the default camelCase.
  • Microsoft.AspNetCore.OpenApi โ€” OpenAPI metadata for development exploration.
dotnet add package Microsoft.AspNetCore.OData
dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson
dotnet add package Microsoft.AspNetCore.OpenApi

2.3 Inspect the configuration

Program.cs registers:

  • โœ… OData with ODataConventionModelBuilder exposing the OrdersDetails model under the entity set name Pivot and mounted at the odata route prefix (so the final URL is /odata/Orders).
  • โœ… NewtonsoftJson with DefaultContractResolver to preserve property casing.
  • โœ… CORS with AllowAnyOrigin for development (restrict this in production).
  • โœ… OpenAPI mapped at /openapi in the Development environment.
// filepath: ODataV4Adaptor/Program.cs
using Newtonsoft.Json.Serialization;
using Microsoft.OData.ModelBuilder;
using ODataV4Adaptor.Models;
using Microsoft.AspNetCore.OData;

var builder = WebApplication.CreateBuilder(args);

// Create an ODataConventionModelBuilder to build the OData model
var modelBuilder = new ODataConventionModelBuilder();

// Register the "Orders" entity set with the OData model builder
modelBuilder.EntitySet<OrdersDetails>("Orders");

// Add services to the container.

builder.Services.AddMvc().AddNewtonsoftJson(options =>
{
  options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});

builder.Services.AddCors(options =>
{
  options.AddDefaultPolicy(policy =>
  {
    policy.AllowAnyOrigin()      // Allow requests from any origin.
          .AllowAnyMethod()       // Allow GET, POST, PUT, DELETE, etc.
          .AllowAnyHeader();      // Allow any request headers.
  });
});

builder.Services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();

builder.Services.AddControllers().AddOData(
    options => options
        .Count()
        .AddRouteComponents("odata", modelBuilder.GetEdmModel()));

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.UseCors();

app.Run();

๐Ÿ”’ Production CORS: Replace AllowAnyOrigin() with policy.WithOrigins("https://yourdomain.com"). ๐Ÿ“Œ Default port: The HTTP launch profile in Properties/launchSettings.json listens on http://localhost:5092. The HTTPS profile exposes https://localhost:7181 alongside http://localhost:5092. Update the URL inside Client/src/App.js if you change this.

2.4 The data model

Models/OrdersDetails.cs defines the entity exposed through OData. It is seeded with two records (OrderID 10001 and 10002) the first time GetAllRecords() is called.

// filepath: ODataV4Adaptor/Models/OrdersDetails.cs
using System.ComponentModel.DataAnnotations;

namespace ODataV4Adaptor.Models
{
    public class OrdersDetails
    {
        public static List<OrdersDetails> order = new List<OrdersDetails>();
        public OrdersDetails()
        {

        }
        public OrdersDetails(
        int OrderID, string CustomerId, int EmployeeId, double Freight)
        {
            this.OrderID = OrderID;
            this.CustomerID = CustomerId;
            this.EmployeeID = EmployeeId;
            this.Freight = Freight;
        }

        public static List<OrdersDetails> GetAllRecords()
        {
            if (order.Count() == 0)
            {
                int code = 10000;
                for (int i = 1; i < 2; i++)
                {
                    order.Add(new OrdersDetails(code + 1, "ALFKI", i + 0, 10.0));
                    order.Add(new OrdersDetails(code + 2, "ANATR", i + 2, 20.0));
                    order.Add(new OrdersDetails(code + 3, "ANTON", i + 1, 30.0));
                    order.Add(new OrdersDetails(code + 4, "BLONP", i + 3, 40.0));
                    order.Add(new OrdersDetails(code + 5, "BOLID", i + 4, 50.0));
                    code += 5;
                }
            }
            return order;
        }
        [Key]
        public int? OrderID { get; set; }
        public string? CustomerID { get; set; }
        public int? EmployeeID { get; set; }
        public double? Freight { get; set; }
    }
}

โ„น๏ธ The endpoint seeds five order records (OrderID 10001 โ€“ 10005) the first time GetAllRecords() is called. Each record carries OrderID, CustomerID, EmployeeID, and Freight (a double? rather than a string). Extend the seed loop to load additional rows.

3. Frontend โ€“ React Pivot Table

The React client lives in the Client/ folder.

3.1 Install npm dependencies

cd ../Client
npm install

3.2 Verify the API URL

Open src/App.js and confirm the url set inside processQuery matches your backend port. The sample uses the HTTP profile (http://localhost:5092).

// filepath: Client/src/App.js
import * as React from 'react';
import { PivotViewComponent } from '@syncfusion/ej2-react-pivotview';
import { DataManager, ODataV4Adaptor } from '@syncfusion/ej2-data';
import { setValue } from '@syncfusion/ej2-base';
import './App.css';

class CustomAdaptor extends ODataV4Adaptor {
    processQuery(dm, query) {
        dm.dataSource.url = 'http://localhost:5092/odata/Orders'; // Here xxxx represents the port number.
        query.addParams('Syncfusion Grid', 'true');               // Add the additional parameter.
        return super.processQuery.apply(this, arguments);
    }

    beforeSend(dm, request, settings) {
        request.headers.set('Authorization', `true`);
        super.beforeSend(dm, request, settings);
    }

    processResponse() {
        let i = 0;
        const original = super.processResponse.apply(this, arguments);
        // Adding serial number.
        if (original.result) {
            original.result.forEach((item) => setValue('SNo', ++i, item));
        }
        return original;
    }
}

function App() {
    // Configure DataManager with the CustomAdaptor.
    const data = new DataManager({
        url: 'http://localhost:5092/odata/Orders',
        adaptor: new CustomAdaptor(),
    });

    const editSettings = {
        allowEditing: true,    // Enables the Edit button and allows users to modify existing records
        allowAdding: true,     // Enables the Add button and allows users to create new records
        allowDeleting: true,   // Enables the Delete button and allows users to remove records
        mode: 'Normal'         // Uses Normal mode (popup dialog) for editing; other options: 'Dialog', 'Batch'
    };

    const dataSourceSettings = {
        dataSource: data,
        expandAll: false,
        rows: [{ name: 'CustomerID' }],
        columns: [{ name: 'OrderID' }],
        values: [{ name: 'EmployeeID' }],
        formatSettings: [{ name: 'Freight', format: 'N0' }],
    };

    let pivotObj;

    // Configure beginDrillThrough event to set the primary key for CRUD operations
    function beginDrillThrough(args) {
        // Iterate through all columns in the drill-through grid
        for (var i = 0; i < args.gridObj.columns.length; i++) {
            // Check if the current column is the primary key column
            if (args.gridObj.columns[i].field === "OrderID") {
                // Mark this column as the primary key
                // This tells DataManager to use this column's value to uniquely identify records
                args.gridObj.columns[i].isPrimaryKey = true;
            } else {
                // Make all other columns visible so users can view and edit them
                args.gridObj.columns[i].visible = true;
                // Configure the edit type for date fields to use a date picker for editing
                if (args.gridObj.columns[i].field === 'OrderDate' || args.gridObj.columns[i].field === 'ShippedDate') {
                    args.gridObj.columns[i].editType = 'datetimepickeredit';
                }
            }
        }
    }

    return (
        <div className='control-section' style={{ margin: 100 }}>
            <PivotViewComponent
                ref={d => pivotObj = d}
                id='PivotView'
                height={350}
                width={700}
                editSettings={editSettings}
                beginDrillThrough={beginDrillThrough}
                dataSourceSettings={dataSourceSettings}>
            </PivotViewComponent>
        </div>
    );
}

export default App;

๐Ÿ”‘ OrderID is marked as the primary key inside the beginDrillThrough event so update and delete operations know which record to target.


โ–ถ๏ธ Running the Application

You need two terminals โ€” one for the backend OData service and one for the React client.

โ–ถ๏ธ Start the Backend (Terminal 1)

cd ODataV4Adaptor
dotnet run

The service will start on http://localhost:5092 (HTTP profile) by default. The HTTPS profile binds https://localhost:7181 and http://localhost:5092 if you select that profile.

Verify it works:

  • ๐ŸŒ Open http://localhost:5092/odata/Orders in your browser.
  • โœ… You should see an OData v4 response: { "@odata.context": "...", "value": [ ... ] }.
  • ๐Ÿ”ข Visit http://localhost:5092/odata/Orders?$count=true to confirm that the inline @odata.count is returned (required for paging).
  • ๐Ÿ“˜ In Development you can also browse http://localhost:5092/openapi for the generated OpenAPI document.

๐Ÿ“ Note the port number in the terminal output and update dm.dataSource.url inside processQuery in Client/src/App.js if it is different from 5092.

โ–ถ๏ธ Start the Frontend (Terminal 2)

cd Client
npm start

The React app will open at http://localhost:3000 by default. ๐ŸŽ‰

You should see the Pivot Table populated with aggregated EmployeeID values, grouped by CustomerID (rows) and OrderID (columns). The serialized response also includes an SNo field on every record that you can verify in the Network tab.

โœ… Verify in the Browser

  1. Open the browser's Developer Tools (F12) โ†’ Network tab.
  2. Reload the page.
  3. You should see a GET request to http://localhost:5092/odata/Orders (with $count=true) that returns status 200 and a JSON response containing @odata.count and value.
  4. Inspect the request headers and confirm Authorization: true is present.
  5. Inspect any record in the response and confirm an SNo field was added by processResponse.
  6. The Pivot Table renders the aggregated data automatically.

๐Ÿงช Testing CRUD Operations

The Pivot Table supports full CRUD through its built-in drill-through editing grid. Because the underlying adaptor is ODataV4Adaptor, the Syncfusionยฎ DataManager issues the standard OData HTTP verbs: GET, POST, PATCH, and DELETE.

Step Action Expected Network Request
1๏ธโƒฃ Double-click any pivot cell to open the drill-through grid showing underlying source records. GET http://localhost:5092/odata/Orders?$count=true
โž• 2๏ธโƒฃ Click Add, fill in the new row fields, then click Update. POST http://localhost:5092/odata/Orders
โœ๏ธ 3๏ธโƒฃ Click Edit on an existing row, change a field, then click Update. PATCH http://localhost:5092/odata/Orders/{OrderID}
๐Ÿ—‘๏ธ 4๏ธโƒฃ Click Delete on a row to remove it. DELETE http://localhost:5092/odata/Orders/{OrderID}
๐Ÿ” 5๏ธโƒฃ The Pivot Table automatically refreshes to display the updated aggregated data from the backend. New GET to /odata/Orders?$count=true

๐Ÿ”‘ The OrderID column is automatically marked as the primary key inside the beginDrillThrough event, so update and delete operations know which record to target. ๐Ÿงช You can also exercise the endpoints directly using the included ODataV4Adaptor.http file in JetBrains Rider / VS Code, or via curl / Postman.


๐Ÿ”ง Troubleshooting

โ“ Issue ๐Ÿ” Symptom โœ… Resolution
๐Ÿšซ Empty Pivot Table Pivot loads with no errors but no rows or values appear. Ensure the OData response contains value (and @odata.count for paging) and that field names match dataSourceSettings (case-sensitive).
404 Not Found Network tab shows a 404 response when the Pivot Table loads. Confirm the backend is running, the OData route is odata/Orders, and the URL in App.js matches the API port.
๐Ÿ’ฅ 500 Internal Server Error The Pivot Table fails and the browser shows a server error. Check the terminal/Visual Studio output for stack traces. Common causes: null reference, missing [EnableQuery], or CORS issues.
๐ŸŒ CORS Blocked Console shows Access to XMLHttpRequest ... has been blocked by CORS policy. Verify CORS is configured in Program.cs and app.UseCors() is called before app.MapControllers().
๐Ÿ’พ CRUD operations not saving The edit dialog closes but changes are not reflected in the data. Confirm the primary key is set in beginDrillThrough and that POST/PATCH/DELETE are mapped on OrdersController.
๐Ÿ”ค Property casing mismatch Pivot appears empty or shows "field not found" even though the API returns data. Ensure DefaultContractResolver is registered in Program.cs so PascalCase fields like OrderID are preserved. Note that this sample uses Freight (double) and OrderID (int) โ€” there is no ShipCountry field.
๐Ÿงฎ Serial numbers missing on records SNo does not appear in the rendered data. Verify processResponse runs super.processResponse first and uses setValue('SNo', ++i, item) on each item.
๐Ÿ›‚ Auth header not visible The Authorization header is missing on the outgoing request. Confirm beforeSend calls request.headers.set('Authorization', ...) and then super.beforeSend.
๐Ÿ” Adaptor does nothing Overrides have no effect. Ensure the DataManager is constructed with new CustomAdaptor() (not new ODataV4Adaptor()) and that super.<method> is called exactly once per method.
๐Ÿ”’ SSL/TLS certificate error Console shows net::ERR_CERT_AUTHORITY_INVALID or browser warns about an untrusted certificate. Run dotnet dev-certs https --clean then dotnet dev-certs https --trust (Windows/macOS). On Linux, use HTTP for local testing.

๐Ÿ“– API Reference

The backend exposes the following endpoints through OrdersController (mounted under the OData route prefix odata, entity set Orders):

Method Route Purpose Request Body Response
GET /odata/Orders Retrieve all order records (supports $filter, $orderby, $top, $skip, $count). โ€” OData v4 payload ({ "@odata.count": N, "value": [...] })
GET /odata/Orders/{key} Retrieve a single order by primary key (OrderID). โ€” 200 OK with the matching order, or 404 Not Found
POST /odata/Orders Insert a new order (prepended to the in-memory list). OrdersDetails JSON 201 Created with the inserted record
PATCH /odata/Orders/{key} Update CustomerID, EmployeeID, and Freight of an existing order (null-coalesced). OrdersDetails JSON 200 OK with the updated record, or 404 Not Found
DELETE /odata/Orders/{key} Remove an order by primary key (OrderID). โ€” 204 No Content, or 404 Not Found

The OrdersDetails model exposes the following fields:

Field Type Description
OrderID int? Unique order identifier (primary key, [Key] annotated).
CustomerID string? Identifier of the customer.
EmployeeID int? Identifier of the handling employee.
Freight double? Shipping cost for the order.

โ„น๏ธ The current controller updates only CustomerID, EmployeeID, and Freight on PATCH. Extend Patch in OrdersController.cs if you need to update other fields.

Data flow summary

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  React Pivot Table       โ”‚         โ”‚  CustomAdaptor           โ”‚         โ”‚  ASP.NET Core OData    โ”‚
โ”‚  (Syncfusionยฎ EJ2)       โ”‚  HTTP   โ”‚  extends ODataV4Adaptor  โ”‚  HTTP   โ”‚  OrdersController      โ”‚
โ”‚                          โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ–บ โ”‚  - processQuery          โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ–บ โ”‚  GET  /odata/Orders     โ”‚
โ”‚  drill-through CRUD โ†’    โ”‚         โ”‚  - beforeSend            โ”‚         โ”‚  POST /odata/Orders     โ”‚
โ”‚  aggregates โ†’ render     โ”‚ โ—„โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚  - processResponse       โ”‚ โ—„โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚  PATCH/PUT/DELETE      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   JSON  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   JSON  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  1. The Pivot Table triggers a query through the DataManager.
  2. CustomAdaptor.processQuery rewrites the URL to http://localhost:5092/odata/Orders and adds the Syncfusion Grid=true query parameter.
  3. CustomAdaptor.beforeSend injects the Authorization header.
  4. The base ODataV4Adaptor serializes the request as OData v4 ($filter, $top, etc.) and calls the backend.
  5. OrdersController honors the query through [EnableQuery] and returns { "@odata.count": N, "value": [...] }.
  6. CustomAdaptor.processResponse walks original.result and adds an SNo field to each item before the Pivot Table renders it.
  7. CRUD operations (POST / PATCH / DELETE) follow the same flow but use the verbs described in the API Reference table.

๐Ÿค Contributing

Contributions are welcome and appreciated! ๐Ÿ’–

  1. ๐Ÿด Fork the repository.
  2. ๐ŸŒฟ Create a feature branch: git checkout -b feature/my-awesome-change
  3. ๐Ÿ’พ Commit your changes: git commit -m "Add my awesome change"
  4. ๐Ÿ“ค Push to your branch: git push origin feature/my-awesome-change
  5. ๐Ÿ” Open a Pull Request describing the change and its motivation.

๐Ÿ“‹ Contribution Guidelines

  • Follow the existing code style in both the React and ASP.NET Core projects.
  • Keep changes focused โ€” one feature or fix per pull request.
  • Update or add documentation (README.md, custom-adaptor.md) when behavior changes.
  • Test your changes locally against both the backend and frontend before submitting.

๐Ÿ“œ License & Support

๐Ÿ“„ License

This project is released under the MIT License. You are free to use, modify, and distribute the code in personal and commercial projects. See the LICENSE file for full text.

๐Ÿ›Ÿ Support

โญ If this project helped you, please consider giving it a star on GitHub โ€” it helps others discover it!


๐Ÿ“š Related Resources


Built with โค๏ธ using React and .NET by the Syncfusionยฎ team.

About

A quick start project that demonstrates how to implement a Custom Adaptor for the Syncfusion React Pivot Table, allowing customized data fetching, request handling, and response processing from external or proprietary data sources.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors