PHPackages                             hesham-fouda/ag-grid-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. hesham-fouda/ag-grid-laravel

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

hesham-fouda/ag-grid-laravel
============================

AG Grid server-side adapter for Laravel.

1.1.2(1y ago)0204↓100%2MITPHPPHP ^8.1|^8.2

Since Sep 16Pushed 1y agoCompare

[ Source](https://github.com/hesham-fouda/ag-grid-laravel)[ Packagist](https://packagist.org/packages/hesham-fouda/ag-grid-laravel)[ Docs](https://github.com/hesham-fouda/ag-grid-laravel)[ RSS](/packages/hesham-fouda-ag-grid-laravel/feed)WikiDiscussions main Synced today

READMEChangelog (4)Dependencies (13)Versions (5)Used By (0)

AG Grid server-side adapter for Laravel
=======================================

[](#ag-grid-server-side-adapter-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/736eae4c826bf4340c56a76ea539c40e4beb467f363d886579773b47ad72d871/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f68657368616d2d666f7564612f61672d677269642d6c61726176656c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/hesham-fouda/ag-grid-laravel)[![GitHub Tests Action Status](https://camo.githubusercontent.com/aa81a45f3f4c4bc6278191f785a48990b5e3b94070ae925c926a0b92e602c318/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f68657368616d2d666f7564612f61672d677269642d6c61726176656c2f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/hesham-fouda/ag-grid-laravel/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/82b18e8473f868d9e2c94451862a6dec0769184d588982bbbee7d7bb239a563a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f68657368616d2d666f7564612f61672d677269642d6c61726176656c2f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/hesham-fouda/ag-grid-laravel/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/42e8a7484fccdd3572cee141f6af2f7f88553be7d3272869c7b406d84ef4883f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f68657368616d2d666f7564612f61672d677269642d6c61726176656c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/hesham-fouda/ag-grid-laravel)

This package implements a server-side adapter for [AG Grid](https://www.ag-grid.com/) with support for filtering, sorting, exporting and server-side selection.

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require hesham-fouda/ag-grid-laravel
```

You can publish the config file with:

```
php artisan vendor:publish --tag="ag-grid-laravel-config"
```

This is the contents of the published config file:

```
return [
    /*
     * The class that contains the provider for determining the timezone
     * to use for DateTime formatting in exports.
     */
    'export_timezone_provider' => \HeshamFouda\AgGrid\AgGridDefaultExportTimezoneProvider::class
];
```

Usage
-----

[](#usage)

### Querying a resource

[](#querying-a-resource)

Simply accept an `AgGridGetRowsRequest` in your controller and return an instance of `AgGridQueryBuilder` for the model that you want to query. Filtering, sorting and exporting is handled automatically for you. You may also pass a JSON resource to the query builder to wrap your models with.

```
class FlamingoGridController extends Controller
{
    public function __invoke(AgGridGetRowsRequest $request): AgGridQueryBuilder
    {
        $query = Flamingo::query()
            ->with(['keeper'])
            ->orderByDesc('id');

        return AgGridQueryBuilder::forRequest($request, $query)
            ->resource(FlamingoResource::class);
    }
}
```

### Set Filter Values

[](#set-filter-values)

When using AG Grid with the `serverSide` row model, you are responsible for providing the values for the set value filter (the frontend only knows a subset of the whole data and therefore cannot know all possible set values).

```
class FlamingoGridSetValuesController extends Controller
{
    public function __invoke(AgGridSetValuesRequest $request)
    {
        $query = Flamingo::query()
            ->with(['keeper']);

        return AgGridQueryBuilder::forSetValuesRequest($request, $query)
            ->toSetValues(['*']);
    }
}
```

See the `AgGridSetValuesRequest` class for the structure of the request.

**IMPORTANT**
You need to whitelist the columns the set filter values can be retrieved for. This can be done be providing an array with the columns/dotted relation:

```
->toSetValues(['name', 'kepper.name']);
```

If your model does not expose any relations or sensitive columns, you can also use `['*']` as wildcard.

Here's an example for the frontend implementation:

```
const colDef = {
    filterParams: {
        excelMode: 'windows',
        values: (parameters: SetFilterValuesFuncParams) => {
            axios
                .post('url',
                    {
                        column,
                        filterModel: parameters.api.getFilterModel(),
                    },
                )
                .then((response) => {
                    parameters.success(response.data)
                }).catch(() => {
                parameters.success([])
            })
        },
    },
}
```

### Server-side select

[](#server-side-select)

When using AG Grid with the `serverSide` row model, you can't just pass the selected IDs to the server when performing a batch operation. In this case, you may pass the current selection state of the grid to the server and resolve the selection there.

To do so, add the following to your request:

```
class FeedFlamingosRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'selection' => ['required', new AgGridSelection()],
            'food_type' => ['required', 'string'],
        ];
    }
}
```

In your controller, use the `AgGridQueryBuilder` to resolve the selection:

```
class FeedFlamingosController extends Controller
{
    public function __invoke(FeedFlamingsRequest $request): AgGridQueryBuilder
    {
        $flamingos = AgGridQueryBuilder::forSelection($request->validated('selection'))->get();

        foreach($flamingos as $flamingo){
            $flamingo->feed($request->validated('food_type'));
        }

        return $flamingos;
    }
}
```

### Exports

[](#exports)

To enable server-side exports for your models, you must implement the `AgGridExportable` interface. After that, you can just pass `exportFormat` as part of your request to the grid controller and the library handles transforming your models into Excel, CSV, or TSV files.

```
class Flamingo extends Model implements AgGridExportable {

    // ... your model definitions

    public static function getAgGridColumnDefinitions(): array
    {
        return [
            new AgGridColumnDefinition(
                'id',
                __('ID'),
            ),
            new AgGridColumnDefinition(
                'name',
                __('Name'),
            ),
            new AgGridColumnDefinition(
                'keeper_id',
                __('Keeper'),
                null,
                fn ($data) => $data->keeper->name,
            ),
            new AgGridColumnDefinition(
                'created_at',
                __('Created At'),
                new AgGridDateFormatter(),
            ),
        ];
    }

}
```

### Custom Filters

[](#custom-filters)

Sometimes you may need to add custom filter scopes or other constraints to the query, which are not covered by the standard AG Grid filters. In this case, you may populate the `customFilters` object of the request with your own data. On the backend side, your model must implement the `AgGridCustomFilterable` interface as shown below:

```
class Flamingo extends Model implements AgGridCustomFilterable {

    use SoftDeletes;

    // ... your model definitions

    public function applyAgGridCustomFilters(Builder $query, array $filters): void
    {
        $query->when($filters['showTrashed'] ?? false, function ($query) {
            return $query->withTrashed();
        });
    }
}
```

Type definitions
----------------

[](#type-definitions)

You may use the following Typescript type definitions as a reference for implementing the requests on the frontend:

```
interface AgGridSelection {
    rowModel: 'serverSide' | 'clientSide'
    selectAll: boolean
    toggledNodes: (string | number)[]
    filterModel?: any
    customFilters?: any
}

interface AgGridGetRowsRequest extends IServerSideGetRowsRequest {
    exportFormat?: 'excel' | 'csv' | 'tsv'
    exportColumns?: string[]
    customFilters?: any
}

interface AgGridGetRowsResponse {
    total: number
    data: T[]
}
```

Frontend implementation
-----------------------

[](#frontend-implementation)

You are free to use any frontend technology or framework of your choice. However, here are some examples that you may use as a starting point four your own implementation

### Creating a DataSource

[](#creating-a-datasource)

In order to use the server-side row model, you must create a data source. Here is an exemplary implementation of such one:

```
 function makeDataSource(
    url: string,
    customFilters?: Record
): IServerSideDatasource {
    return {
        // called by the grid when more rows are required
        async getRows(parameters) {
            const request = {
                ...parameters.request,
                customFilters,
            }
            // get data for request from server
            try {
                const response = await axios.post(url, request)
                parameters.success({
                    rowData: response.data.data,
                    rowCount: response.data.total,
                })
            } catch {
                parameters.fail()
            }
        },
    }
}
```

### Triggering a server-side export

[](#triggering-a-server-side-export)

Server-side exports are not implemented in AG Grid by default. However you can create a custom context menu or add a button somewhere that triggers the server-side export. The handler function may look something like this:

```
async function exportServerSide(grid: GridApi, format: 'excel' | 'csv' | 'tsv', onlySelected: boolean) {
    // using a private api here to oget the ssrm parameters
    const parameters = api.getModel().getRootStore().getSsrmParams()
    // only request the visible columns
    const cols = columnApi?.getAllDisplayedColumns().map((column) => column.getColId())
    // download the file
    const response = await axios.post(
        props.dataSourceUrl!,
        {
            ...parameters,
            ...(onlySelected ? api.getServerSideSelectionState() : {}),
            exportFormat: format,
            exportColumns: cols,
        },
        {
            responseType: 'blob',
        }
    )
    // create an object url from the response
    const url = URL.createObjectURL(response.data)
    // create a link to trigger the download
    const a = document.createElement('a')
    a.href = url
    a.download = true
    a.click()
}
```

### Tracking selection state

[](#tracking-selection-state)

If you want to use server-side selects, you must track the current selection and filter state of the grid:

```
// use the selection in any batch requests to the server
let selection: AgGridSelection

function onSelectionChanged(event: SelectionChangedEvent) {
    if (event.api.getModel().getType() !== 'serverSide') {
        throw new Error('Only the serverSide row model is supported.')
    }

    const selectionState = event.api.getServerSideSelectionState() as IServerSideSelectionState
    selection = {
        rowModel: 'serverSide',
        selectAll: selectionState.selectAll,
        toggledNodes: selectionState.toggledNodes,
        filterModel: event.api.getFilterModel()
    }
}

function onFilterChanged(event: FilterChangedEvent) {
    if (!selection) {
        return
    }

    selection.filterModel = event.api.getFilterModel()
}
```

Limitations
-----------

[](#limitations)

- Only works with PostgreSQL as a storage backend due to some special SQL operators being used in set and json queries.
- Does not support multiple conditions per filter (AND, OR)
- Does not support server-side grouping for AG Grid's pivot mode
- Filtering for values in relations is only supported one level deep. E.g you can filter for `relation.value` but not `relation.otherRelation.value`

TODOs
-----

[](#todos)

- Implement set filter for nested json fields
- Implement multiple conditions per filter (`AND`, `OR`)
- Add type-safe data structures for selection and request data
- Test with mysql

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Credits
-------

[](#credits)

- [HeshamFouda](https://github.com/hesham-fouda)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

32

—

LowBetter than 74% of packages

Maintenance38

Infrequent updates — may be unmaintained

Popularity14

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 68.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~6 days

Total

4

Last Release

532d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/1da9c7b76693fd6dff979ebcc864d67ea9e92fee6051a65b03959695da520331?d=identicon)[etchfoda](/maintainers/etchfoda)

---

Top Contributors

[![fl0cke](https://avatars.githubusercontent.com/u/3774918?v=4)](https://github.com/fl0cke "fl0cke (22 commits)")[![hesham-fouda](https://avatars.githubusercontent.com/u/15731469?v=4)](https://github.com/hesham-fouda "hesham-fouda (5 commits)")[![saibotk](https://avatars.githubusercontent.com/u/10776964?v=4)](https://github.com/saibotk "saibotk (2 commits)")[![ahawlitschek](https://avatars.githubusercontent.com/u/53199186?v=4)](https://github.com/ahawlitschek "ahawlitschek (1 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

laravelag-grid-laravel

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/hesham-fouda-ag-grid-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/hesham-fouda-ag-grid-laravel/health.svg)](https://phpackages.com/packages/hesham-fouda-ag-grid-laravel)
```

###  Alternatives

[konnco/filament-import

241239.5k2](/packages/konnco-filament-import)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
