Aggrid Php Example Updated May 2026
Create api/get-rows.php. This is the core updated AG Grid PHP example.
Key updates from old tutorials:
<?php // api/get-rows.php header('Content-Type: application/json'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: POST, OPTIONS'); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') exit(0);require_once '../config/database.php';
$input = json_decode(file_get_contents('php://input'), true);
$startRow = (int)($input['startRow'] ?? 0); $endRow = (int)($input['endRow'] ?? 20); $limit = $endRow - $startRow; $offset = $startRow;
$sortModel = $input['sortModel'] ?? []; $filterModel = $input['filterModel'] ?? [];
$pdo = getConnection();
// ---------- Build WHERE clause dynamically ---------- $whereClause = ""; $params = [];
foreach ($filterModel as $colId => $filter) $value === '') continue; if ($filterType === 'text') $type = $filter['type'] ?? 'contains'; switch ($type) case 'contains': $whereClause .= " AND `$colId` LIKE :$colId_cont"; $params[":$colId_cont"] = "%$value%"; break; case 'equals': $whereClause .= " AND `$colId` = :$colId_eq"; $params[":$colId_eq"] = $value; break; case 'startsWith': $whereClause .= " AND `$colId` LIKE :$colId_start"; $params[":$colId_start"] = "$value%"; break; case 'endsWith': $whereClause .= " AND `$colId` LIKE :$colId_end"; $params[":$colId_end"] = "%$value"; break; elseif ($filterType === 'number') $type = $filter['type'] ?? 'equals'; switch ($type) case 'equals': $whereClause .= " AND `$colId` = :$colId_eq"; $params[":$colId_eq"] = $value; break; case 'greaterThan': $whereClause .= " AND `$colId` > :$colId_gt"; $params[":$colId_gt"] = $value; break; case 'lessThan': $whereClause .= " AND `$colId` < :$colId_lt"; $params[":$colId_lt"] = $value; break; elseif ($filterType === 'date') $date = date('Y-m-d H:i:s', strtotime($value)); $whereClause .= " AND DATE(`$colId`) = :$colId_date"; $params[":$colId_date"] = $date;
// ---------- Build ORDER BY clause ----------
$orderClause = "";
if (!empty($sortModel))
$sorts = [];
foreach ($sortModel as $sort)
$col = $sort['colId'];
$dir = strtoupper($sort['sort']) === 'ASC' ? 'ASC' : 'DESC';
$sorts[] = "$col $dir";
$orderClause = " ORDER BY " . implode(", ", $sorts);
// ---------- Get total row count (for lastRow) ---------- $countSql = "SELECT COUNT(*) FROM products WHERE 1=1 $whereClause"; $countStmt = $pdo->prepare($countSql); foreach ($params as $key => $val) $countStmt->bindValue($key, $val); $countStmt->execute(); $totalRows = (int)$countStmt->fetchColumn();
// ---------- Get paginated data ---------- $sql = "SELECT id, product_name, category, price, stock_quantity, last_updated FROM products WHERE 1=1 $whereClause $orderClause LIMIT :limit OFFSET :offset";
$stmt = $pdo->prepare($sql);
// Bind filter params foreach ($params as $key => $val) $stmt->bindValue($key, $val); $stmt->bindValue(':limit', $limit, PDO::PARAM_INT); $stmt->bindValue(':offset', $offset, PDO::PARAM_INT); $stmt->execute(); aggrid php example updated
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Return AG Grid expected structure echo json_encode([ 'rows' => $rows, 'lastRow' => $totalRows ]);
database.php (config file):
<?php // config/database.php function getConnection() $host = 'localhost'; $db = 'your_database'; $user = 'your_user'; $pass = 'your_password'; $charset = 'utf8mb4';$dsn = "mysql:host=$host;dbname=$db;charset=$charset"; $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]; return new PDO($dsn, $user, $pass, $options);
Create an index.html file using AG Grid v31+ with the server-side row model.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>AG Grid PHP Example – Updated Server-Side</title> <script src="https://cdn.jsdelivr.net/npm/ag-grid-community@31.3.2/dist/ag-grid-community.min.js"></script> <style> html, body height: 100%; margin: 0; .ag-theme-alpine height: 90vh; width: 100%; </style> </head> <body> <div id="myGrid" class="ag-theme-alpine"></div><script> // Define columns const columnDefs = [ field: "id", sortable: true, filter: "agNumberColumnFilter" , field: "product_name", headerName: "Product Name", sortable: true, filter: "agTextColumnFilter" , field: "category", sortable: true, filter: "agSetColumnFilter" , field: "price", sortable: true, filter: "agNumberColumnFilter" , field: "stock_quantity", headerName: "Stock", sortable: true , field: "last_updated", headerName: "Last Updated", sortable: true, filter: "agDateColumnFilter" ]; // Server-side datasource const dataSource = getRows: async (params) => const request = startRow: params.request.startRow, endRow: params.request.endRow, sortModel: params.request.sortModel, filterModel: params.request.filterModel ; try const response = await fetch('http://localhost/aggregid-php/api/get-rows.php', method: 'POST', headers: 'Content-Type': 'application/json' , body: JSON.stringify(request) ); const result = await response.json(); params.successCallback(result.rows, result.lastRow); catch (error) console.error('AG Grid fetch failed:', error); params.failCallback(); ; const gridOptions = columnDefs: columnDefs, rowModelType: 'serverSide', serverSideStoreType: 'partial', cacheBlockSize: 100, pagination: true, paginationPageSize: 100, animateRows: true ; const gridDiv = document.querySelector('#myGrid'); const gridApi = agGrid.createGrid(gridDiv, gridOptions); gridApi.setGridOption('serverSideDatasource', dataSource); </script>
</body> </html>
fetch() API to pull JSON from api.php. This decouples the frontend from the backend, allowing for AJAX refreshes.AG Grid’s server-side row model requires specific request parameters. We’ll build a RESTful endpoint that handles:
File: db.php (PDO connection)
<?php header('Content-Type: application/json'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE'); header('Access-Control-Allow-Headers: Content-Type');$host = 'localhost'; $dbname = 'aggrid_demo'; $user = 'root'; $pass = '';
try $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); catch(PDOException $e) die(json_encode(['error' => 'Database connection failed'])); ?>
File: server.php (main API logic)
<?php require_once 'db.php';$request_method = $_SERVER['REQUEST_METHOD']; $input = json_decode(file_get_contents('php://input'), true);
// Handle GET request for grid data if ($request_method === 'GET' && isset($_GET['action']) && $_GET['action'] === 'getRows') // Extract AG Grid request parameters $startRow = isset($_GET['startRow']) ? (int)$_GET['startRow'] : 0; $endRow = isset($_GET['endRow']) ? (int)$_GET['endRow'] : 100; $limit = $endRow - $startRow;
$sortModel = isset($_GET['sortModel']) ? json_decode($_GET['sortModel'], true) : []; $filterModel = isset($_GET['filterModel']) ? json_decode($_GET['filterModel'], true) : []; // Base query $sql = "SELECT * FROM products"; $countSql = "SELECT COUNT(*) as total FROM products"; $params = []; // Build WHERE clause from filterModel $whereClauses = []; if (!empty($filterModel)) foreach ($filterModel as $field => $filter) if ($filter['filterType'] === 'text') $whereClauses[] = "$field LIKE :$field"; $params[":$field"] = '%' . $filter['filter'] . '%'; elseif ($filter['filterType'] === 'number') if (isset($filter['filter'])) $whereClauses[] = "$field = :$field_eq"; $params[":$field_eq"] = $filter['filter']; if (isset($filter['filterTo'])) $whereClauses[] = "$field <= :$field_to"; $params[":$field_to"] = $filter['filterTo']; if (!empty($whereClauses)) $whereStr = " WHERE " . implode(" AND ", $whereClauses); $sql .= $whereStr; $countSql .= $whereStr; // Build ORDER BY from sortModel if (!empty($sortModel)) $orderBy = []; foreach ($sortModel as $sort) $orderBy[] = "$sort['colId'] $sort['sort']"; $sql .= " ORDER BY " . implode(", ", $orderBy); // Add LIMIT for pagination $sql .= " LIMIT $startRow, $limit"; // Get total row count (without pagination) $totalStmt = $pdo->prepare($countSql); foreach ($params as $key => &$val) $totalStmt->bindParam($key, $val); $totalStmt->execute(); $totalRows = $totalStmt->fetch(PDO::FETCH_ASSOC)['total']; // Get paginated data $stmt = $pdo->prepare($sql); foreach ($params as $key => &$val) $stmt->bindParam($key, $val); $stmt->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); // Return AG Grid expected format echo json_encode([ 'success' => true, 'rows' => $rows, 'lastRow' => $totalRows ]); exit;// Handle POST to add a new row if ($request_method === 'POST' && isset($_GET['action']) && $_GET['action'] === 'addRow') $stmt = $pdo->prepare("INSERT INTO products (name, category, price, stock) VALUES (:name, :category, :price, :stock)"); $stmt->execute([ ':name' => $input['name'], ':category' => $input['category'], ':price' => $input['price'], ':stock' => $input['stock'] ]); echo json_encode(['success' => true, 'id' => $pdo->lastInsertId()]); exit;
// Handle PUT to update a row if ($request_method === 'PUT' && isset($_GET['action']) && $_GET['action'] === 'updateRow') $stmt = $pdo->prepare("UPDATE products SET name=:name, category=:category, price=:price, stock=:stock WHERE id=:id"); $stmt->execute([ ':id' => $input['id'], ':name' => $input['name'], ':category' => $input['category'], ':price' => $input['price'], ':stock' => $input['stock'] ]); echo json_encode(['success' => true]); exit;
// Handle DELETE if ($request_method === 'DELETE' && isset($_GET['action']) && $_GET['action'] === 'deleteRow') $id = $_GET['id']; $stmt = $pdo->prepare("DELETE FROM products WHERE id = ?"); $stmt->execute([$id]); echo json_encode(['success' => true]); exit; ?>
This updated AG Grid PHP example provides a fully functional, enterprise-ready data grid with server-side sorting, filtering, pagination, and CRUD operations. The backend uses modern PHP (8.1+) with PDO, and the frontend leverages AG Grid v31’s server-side row model for optimal performance even with thousands of rows.
Next steps: Integrate AG Grid Enterprise features like Excel export, charting, or master/detail views, and enhance PHP with input validation, logging, and rate limiting for production deployment.
File structure recap:
aggrid-php-example/
├── index.html
├── server.php
├── db.php
└── (optional) .env for credentials
Run with php -S localhost:8000 and open http://localhost:8000. Your AG Grid will communicate seamlessly with the PHP backend, handling all dynamic data operations in real time.
Integrating AG Grid with a PHP backend allows you to handle massive datasets with high-performance features like filtering, sorting, and pagination. Because AG Grid is a client-side library, the "PHP connection" is actually an API bridge where PHP serves JSON data to the grid. Building a Modern AG Grid & PHP Integration 🛠️ The Stack Frontend: AG Grid (Community or Enterprise) Backend: PHP 8.x (Vanilla or Framework) Database: MySQL / PostgreSQL Communication: Fetch API (JSON) 1. The Frontend (index.html)
You need to define the grid container and tell AG Grid where to fetch the data.
Use code with caution. Copied to clipboard 2. The Backend (data.php)
Your PHP script acts as a data provider. It queries the database and returns a JSON array.
query("SELECT id, name, email, created_at FROM users"); $results = $stmt->fetchAll(PDO::FETCH_ASSOC); // Send JSON response echo json_encode($results); catch (PDOException $e) http_response_code(500); echo json_encode(['error' => $e->getMessage()]); ?> Use code with caution. Copied to clipboard 🚀 Key Optimization Strategies 🔹 Server-Side Row Model (SSRM)
For datasets with millions of rows, don't load everything at once.
Client side: Requests a specific "block" of rows (e.g., rows 100-200). PHP side: Uses LIMIT and OFFSET in the SQL query. Benefit: Keeps the browser memory usage low. 🔹 Security Best Practices
PDO Prepared Statements: Always use prepared statements to prevent SQL injection.
CORS: If your frontend and backend are on different domains, configure Access-Control-Allow-Origin headers.
Sanitization: Use json_encode() to ensure data types are preserved correctly. 🔹 Handling Updates (CRUD) To make the grid editable: Enable editable: true in columnDefs. Use the onCellValueChanged event in AG Grid.
Send a POST or PUT request to a save.php script with the updated row data. 💡 Why this works in 2026
Modular JS: Works with Vite, Webpack, or simple tags.
PHP 8 Attributes: Can be used to map database entities directly to JSON.
Performance: AG Grid handles the DOM rendering; PHP handles the heavy data lifting. To help you build a more specific example, let me know:
Are you using a framework (like Laravel or Symfony) or Vanilla PHP?
Do you need to handle Server-Side Filtering (filtering via SQL) or client-side?
I can provide the exact SQL queries or API routes based on your choice!
Integrating AG Grid with PHP is a powerful way to handle large datasets with a modern, high-performance UI. Because PHP is a server-side language and AG Grid is a client-side JavaScript library, the bridge between them is typically a RESTful API that handles data fetching and updates. The Modern Architecture
In an updated stack, you move away from rendering HTML tables on the server. Instead, PHP acts as the backend engine—using a framework like Laravel or a simple Slim app—to serve JSON. AG Grid sits on the frontend, consuming that JSON. This separation allows for "Server-Side Row Model" features, where the grid only loads the data visible to the user, making it capable of handling millions of rows without crashing the browser. Data Fetching and CRUD An effective implementation involves a few key steps:
The API Endpoint: A PHP script queries your database (like MySQL) and returns the result as json_encode($data).
The Grid Configuration: On the frontend, you define columnDefs and use the fetch() API to pull from your PHP endpoint.
Updates: By using AG Grid's onCellValueChanged event, you can send an asynchronous POST or PUT request back to a PHP script to save changes to the database instantly. Security and Performance
Modern examples prioritize prepared statements (PDO) in PHP to prevent SQL injection. Additionally, with the latest AG Grid updates, you can leverage Integrated Charts and Advanced Filtering, which requires passing complex filter objects from the grid to your PHP logic to dynamically build the SQL query.
This script acts as your API. It connects to a database and returns data in JSON format, which AG Grid expects. query( "SELECT id, name, email, role FROM users" ); $data = $stmt->fetchAll(PDO::FETCH_ASSOC); json_encode($data); (PDOException $e) json_encode([ => $e->getMessage()]); ?> Use code with caution. Copied to clipboard 2. The Frontend (index.html)
You include the AG Grid library via CDN and use JavaScript to initialize the grid and fetch data from your PHP script. < >AG Grid PHP Example "https://jsdelivr.net" "ag-theme-alpine" "height: 500px; width:100%;" > const columnDefs = [ field: , sortable: true, filter: true , field:
, sortable: true, filter: true, editable: true , field: , filter: true , field:
];
const gridOptions =
columnDefs: columnDefs,
pagination: true,
// Capture updates to cells
onCellValueChanged: (params) =>
console.log( 'Data updated:'</p>
, params.data); // Here you would use fetch() to POST updates back to a PHP script ;
// Initialize the grid
const gridDiv = document.querySelector(</p>
); const gridApi = agGrid.createGrid(gridDiv, gridOptions);
// Fetch data from PHP backend
fetch( 'data.php'</p>
) .then(response => response.json()) .then(data => gridApi.setGridOption( , data)); Use code with caution. Copied to clipboard Key Integration Points Data Fetching : Use the standard API in JavaScript to call your PHP script and then use setGridOption('rowData', data) to populate the grid. Updating Data : To save changes made by users, listen for the onCellValueChanged
event. You can then send the updated row data back to a PHP script using Grid Methods
: For more complex updates, such as programmatically changing a single cell, you can use grid API methods like rowNode.setDataValue(col, value) Row Selection
: If you need to perform actions on specific rows, enable selection and use gridApi.getSelectedRows() to retrieve the data for processing.
For developers who prefer a more "plug-and-play" PHP solution, alternatives like offer simplified rendering with fewer lines of code. PHP code for handling the POST request to save these grid updates to your database? How to get the data of selected rows in ag-Grid
How to get the data of selected rows in AG Grid * Enable Row Selection. Enable row selection in AG Grid using the grid options. .. AG Grid Blog JavaScript Data Grid - Updating Data - AG Grid
Integrating typically involves a frontend client (JavaScript) requesting data from a backend script (PHP) that queries a database (like MySQL). In modern versions like AG Grid 33 , the process is streamlined by utilizing the createGrid API and the Server-Side Row Model (SSRM) for large datasets. 1. Frontend: The JavaScript Grid The grid requires a container and a configuration object ( gridOptions ). For large datasets, use rowModelType: 'serverSide' to fetch only the data needed for the current view. "height: 500px;" "ag-theme-alpine"
"https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js" > const gridOptions = columnDefs: [ field: 'agNumberColumnFilter' , field: 'agTextColumnFilter' , field:
], // For large datasets (Requires AG Grid Enterprise) rowModelType: 'serverSide' , pagination: true, paginationPageSize: ;
const myGridElement = document.querySelector(
); const api = agGrid.createGrid(myGridElement, gridOptions);
// Define how to fetch data from your PHP backend const datasource = getRows: (params) => fetch( 'backend.php' , method:
, body: JSON.stringify(params.request), headers: 'Content-Type' 'application/json'
) .then(response => response.json()) .then(data => params.success( rowData: data.rows, rowCount: data.total ); ) .catch(() => params.fail()); ;
api.setGridOption( 'serverSideDatasource' , datasource); </ Use code with caution. Copied to clipboard createGrid
is the updated method for instantiating grids in recent versions. 2. Backend: The PHP Script ( backend.php
The backend script receives a JSON request containing sorting, filtering, and row range ( $start = $request[ 'startRow' ; $limit = ($request[ ) - $start; // Example Database Connection (PDO) "mysql:host=localhost;dbname=test"
// Build dynamic SQL based on AG Grid request (simplified for example) "SELECT * FROM users LIMIT :start, :limit" ; $stmt = $pdo->prepare($sql); $stmt->bindValue( , (int)$start, PDO::PARAM_INT); $stmt->bindValue(
, (int)$limit, PDO::PARAM_INT); $stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $total = $pdo->query( "SELECT COUNT(*) FROM users" )->fetchColumn(); json_encode([ => (int)$total ]); Use code with caution. Copied to clipboard 3. Key Framework Integrations
If you are using a modern PHP framework, there are pre-built adapters to handle the complex SQL generation for sorting and grouping: ag-grid-laravel adapter to automatically handle AgGridQueryBuilder contributed module exists for integrating AG Grid into Drupal views. 4. Implementation Best Practices
Building a robust data grid in PHP doesn't have to be complicated. By combining AG Grid's powerful frontend features with a clean PHP backend, you can handle massive datasets with ease.
This guide provides a modern, updated approach to integrating AG Grid with PHP and MySQL using the latest Fetch API and JSON best practices. 🏗️ The Architecture
To create a functional AG Grid PHP example, you need three core components: The Database: A MySQL table to store your data.
The Backend (PHP): A script to fetch data and return it as JSON.
The Frontend (HTML/JS): The AG Grid configuration that consumes the JSON. 1. Setup the Database
First, create a simple table and populate it with sample data.
CREATE DATABASE grid_db; USE grid_db; CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), email VARCHAR(100), role VARCHAR(50), status VARCHAR(20) ); INSERT INTO users (name, email, role, status) VALUES ('Alice Smith', 'alice@example.com', 'Admin', 'Active'), ('Bob Jones', 'bob@example.com', 'User', 'Inactive'), ('Charlie Brown', 'charlie@example.com', 'Editor', 'Active'); Use code with caution. 2. Create the Backend (data.php)
This script connects to your database and outputs the results in a format AG Grid understands. We use PDO for security and json_encode for the response.
PDO::ATTR_ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]; try $pdo = new PDO($dsn, $user, $pass, $options); $stmt = $pdo->query("SELECT id, name, email, role, status FROM users"); $data = $stmt->fetchAll(); echo json_encode($data); catch (\PDOException $e) echo json_encode(['error' => $e->getMessage()]); ?> Use code with caution. 3. Build the Frontend (index.html)
In this updated version, we use the AG Grid Community CDN and the modern Fetch API to retrieve our PHP data.
Create a MySQL database and add a table with some sample data. For this example, we'll use a simple table called "employees" with the following columns:
| id | name | email | department |
| --- | --- | --- | --- |
| 1 | John Smith | john.smith@example.com | Sales |
| 2 | Jane Doe | jane.doe@example.com | Marketing|
| 3 | Bob Brown | bob.brown@example.com | IT |
In this example, we've created a simple AG Grid table using PHP and MySQL. We've demonstrated how to fetch data from a database and display it in an interactive table. AG Grid offers a wide range of features and customization options, making it a powerful tool for creating dynamic and interactive tables.