Cartalyst LLC.
Data-grid by Cartalyst
4
115
0
14
0

This package requires a valid subscription. Subscribe for access.

Introduction

DataGrid is a framework agnostic data grid package that makes it fantastically easy to handle large data sources. It shifts the focus from pagination to data filtration. Pass any data source through a data handler and the package will take care of the rest so you can use the filtered result set to create your applications.

The package requires PHP 8.0+ and follows the FIG standard PSR-4 to ensure a high level of interoperability between shared PHP code and is fully unit-tested.

Philosophy

We wanted to create a package that would not only simplify front end side of presenting a data set, but make it easy to handle any data set in general.

No matter what is the use case, data-grid's goal is to help you manage and manipulate your data set.

We completely rewrote data-grid to be very flexible and extendable for a wide range of use cases, from creating a full-fledged facets enabled e-commerce catalog to internal use of data-grid for your backend.

Have a read through the Installation Guide and on how to integrate it with other frameworks using our implementation and bridge packages.

Features

Data-grid comes with the following built-in features:

Back end

  • Filtration. Data-grid supports various filters, operators and regex match.
  • Sorting. You can sort your data by multiple sort criteria.
  • Pagination. You can easily paginate your data, and additionally set up one of built-in pagination methods - such as infinite, single, or grouped.
  • Hydrator. No matter what is your data source, data-grid can hydrate resulting data-set into any other data structure, for instance, your application models.
  • Transformer. While hydrator is very useful when you want to have your models for further use, you still might need to change what your view sees. Transformer solves that, pass a transformer to your data handler settings and data-grid will call it before returning the results to the view.

Note: Both hydrator and transformer can either be passed into your data handler settings as closures, or implement provided interface contracts.

Front end

On the front end data-grid comes with fully customizable js component which provides the following features.

  • Layouts. Instead of predefined templates data-grid comes with flexible layout system allowing the creation of modern dynamic UI.
  • Filters. New filters allow you to easily customize the filter behavior and to add your own filter types. You can define you filters via our streamlined DOM API, or as filter presets via constructor options.
  • Events. You can observe each phase of the data-grid lifecycle and change the behavior with improved events, each of them providing more context on what exactly has happened.
  • History states. Cleaner urls.

Quick Example

use App\Models\Post;
use Cartalyst\DataGrid\DataGrid;
use Cartalyst\DataGrid\DataHandlers\CollectionHandler;

$settings = [
    'columns' => ['id', 'slug', 'title'],
];

$handler = new CollectionHandler(Post::all(), $settings);

return DataGrid::make($handler);

Setup

Installation

Cartalyst packages utilize Composer, for more information on how to install Composer please read the Composer Documentation.

Preparation

Open your composer.json file and add the following to the require array:

"cartalyst/data-grid": "^8.0"

Add the following lines after the require array on your composer.json file:

"repositories": [
    { "type": "composer", "url": "https://packages.cartalyst.com" }
]

Note: Make sure that after the required changes your composer.json file is valid by running composer validate.

Install the dependencies

Run the composer install or composer update to install or update the new requirement.

Usage

In this section we'll show how you can utilize the data grid package.

Cartalyst's Data Grid package provides a couple of ways to interact with. The most basic way is to instantiate the Cartalyst\DataGrid\DataGrid class with Cartalyst's default built-in Cartalyst\DataGrid\DataHandlers\CollectionHandler for data handling.

After creating a Data Grid object you can use the data handler to interact with your result set.

Creating a Data Grid Object

Creating a Data Grid object can be done by calling the make function on the Data Grid environment.

$handler = new CollectionHandler($data, $settings);
$dataGrid = DataGrid::make($handler);

The $data variable must contain all of the data you want to filter. This can be any sort of data type as long as it can be handled by your data handlers. The $settings variable must contain an array of the settings, including the columns for each data object to include in the result set.

Calling the make helper method on the DataGrid class will send back an instance of Cartalyst\DataGrid\DataGrid.

The data provided for CollectionHandler can hold data objects of the following types:

  • An array
  • An object which is an instance of or extends the stdClass object
  • An object which has toArray method

A basic example of creating a Data Grid object could be:

$object = new StdClass;
$object->title = 'foo';
$object->age = 20;

$data = [
    [
        'title' => 'bar',
        'age'   => 34,
    ],
    $object,
];

$settings = [
    'columns' => [
        'title',
        'age',
    ]
];

$handler = new CollectionHandler($data, $settings);
$dataGrid = DataGrid::make($handler);

Note: If a data object in the $data set doesn't have a column set in the columns settings, it will return null in the result set for that column.

You can also rename columns by defining them as a key/value pair with the original name being the key and the new name being the value.

$handler = new CollectionHandler($data, [
    'columns' => [
        'title' => 'new_title_column_name',
        'age'   => 'new_age_column_name',
    ]
]);

Settings

Settings can be passed as a second parameter to the DataHandler constructor.

$handler = new CollectionHandler($data, [
    'columns' => ['title', 'age'],
    'sort' => [
        'column'    => 'age',
        'direction' => 'desc'
    ]
]);

Below is a list of available options

Option Type Default Description
sort array Default sort if no sort has been provided.
method string null Default method if no throttle has been provided.
throttle int null Default throttle if no throttle has been provided.
threshold int null Default threshold if no throttle has been provided.

Concepts

Provider

Cartalyst\DataGrid\Contracts\Provider is a contract that handles request params and data-grid's dispatch requests. Data-grid has two default implementations.

RequestProvider

Filter, sort and pagination params are parsed from http request.

use App\Models\Post;
use Cartalyst\DataGrid\DataGrid;
use Cartalyst\DataGrid\DataHandlers\CollectionHandler;
use Cartalyst\DataGrid\Providers\RequestProvider;
use Symfony\Component\HttpFoundation\Request;

$settings = [
    'columns' => ['id', 'slug', 'title'],
];

$handler = new CollectionHandler(Post::all(), $settings);
$provider = RequestProvider(Request::createFromGlobals());

return DataGrid::make($handler, $provider);

Note: You don't need to set up RequestProvider, it will be instantiated by default.

ArrayProvider

Params will be instantiated from an array.

use App\Models\Post;
use Cartalyst\DataGrid\DataGrid;
use Cartalyst\DataGrid\DataHandlers\CollectionHandler;

$settings = [
    'columns' => ['id', 'slug', 'title'],
];

$handler = new CollectionHandler(Post::all(), $settings);
$provider = RequestProvider(Request::createFromGlobals());

return DataGrid::make($handler, [
    'filters' => [
        ['country' => 'US'],
        ['state' => 'New Mexico'],
    ],
    'sort' => [
        ['column' => 'population’, 'direction' => 'desc']
    ],
    'page' => 1,
]);

Handler

The data handler is the class that handles and filters the data you passed along. In the examples below we'll go over the functionality of the data handler.

Collection Handler

The collection handler can handle the following types of data.

  • Cartalyst Collection objects
  • Arrays with data objects which could be:
    • An array
    • An object which is an instance of or extends the stdClass object
    • An object which can be transformed to an array (i.e. has toArray method)

If you'd like to use the CollectionHandler data handler you need to pass it to Data Grid.

use Illuminate\Support\Collection;
use Cartalyst\DataGrid\DataHandlers\CollectionHandler;

$collection = Collection::make($array);
$handler = new CollectionHandler($collection, $settings);
// or $handler = new CollectionHandler($array, $settings);

$dataGrid = DataGrid::make($handler);

Database Handler

The database handler can handle the following types of data.

  • Queries
  • Query results
  • Eloquent Models & Relationships

If you'd like to use the DatabaseHandler data handler you need to add data-grid-laravel package to your composer requirements.

use Cartalyst\DataGrid\Laravel\DataHandlers\DatabaseHandler;
use App\MyModel;

$handler = new DatabaseHandler(new MyModel(), $settings);
// or $handler = new DatabaseHandler(DB::table('my_table'), $settings);

$dataGrid = DataGrid::make($handler);

Note: In order to use Database Handler, you need to use data-grid-laravel add-on. Check out the docs on integration with Laravel.

Custom Data Handlers

In addition to the default data handlers provided by the package, you can create your own custom data handlers as well. All data handlers need to extend the abstract Cartalyst\DataGrid\DataHandlers\BaseHandler class.

use Cartalyst\DataGrid\DataHandlers\BaseHandler;

class CustomHandler extends BaseHandler {

}

Specific handlers can be created to handle specific sets of data like framework specific result sets or a certain service's API result responses.

Parameters

Data Handler provides ParameterBag object with result set parameters.

$params = $handler->getParams();

Get the total amount of results.

$totalCount = $params->get('total');

Get the total amount of filtered results.

$filteredCount = $params->get('filtered');

Get the current page.

$page = $params->get('page');

Get the number of pages.

$pagesCount = $params->get('pages');

Get the previous page.

$previousPage = $params->get('previous_page');

Get the next page.

$nextPage = $params->get('next_page');

Get the number of results per page.

$perPage = $params->get('per_page');

Note: Parameters will be returned to the response along with the results, so in case you need to change the output, it should be done in your custom handler.

Result Sets

After instantiating a Data Grid object you have a couple of options to work with the data result sets. Depending on the request provider which you registered with your environment, the implementation of these methods can differ. In the examples below we're going to assume you're using the default Cartalyst\DataGrid\Providers\RequestProvider request provider.

You can filter results by sending specific request parameters along with your HTTP request. Your request provider will catch these so your data handler can filter the data based on these request parameters.

Generating Results

You can convert the result set from the Data Grid object to an array or JSON response by calling the toArray or toJson functions.

use Cartalyst\DataGrid\DataGrid;

$dataGrid = DataGrid::make($handler);

// Retrieve the result set as an array.
$array = $dataGrid->toArray();

// Retrieve the result set as a JSON response.
$json = $dataGrid->toJson();

The returned response would look something like this:

{
    "total": 3,
    "filtered": 3,
    "page": 1,
    "pages": 1,
    "previous_page": null,
    "next_page": null,
    "per_page": 3,
    "sort": {
        "column": "name",
        "direction": "asc",
    },
    "results": [
        {
            "name": "John Doe",
            "age": 22,
            "location": "New York"
        },
        ...
    ]
}

The response contains some useful information like the total number of results, the amount of filtered results, the current, previous and next page and a list with all of the results for the current page.

Note: When sending the Data Grid object to the browser, it will be automatically converted to a JSON response. This is very useful, for example, when building APIs.

Sorting Results

You can sort the result set by sending a request parameter with the sort key.

http://example.com/grid?sort[0][column]=name&sort[0][direction]=desc

This will sort the results by name in descending order.

Switching Pages

Changing the page in a result set can be done by sending a request parameter with the page key.

http://example.com/grid?page=2

This would show the results on the second page of the result set.

Filter Results

You can filter results by sending a request parameter with the filters key. The filters request parameter must provide filters based as a key (column) and value (column value) array.

For example:

http://testing.loc/grid?filters[name]=foo&filters[age]=24

This would show only results which have a foo name and an age of 24.

Paginating Results

There are three request parameters you can use to paginate a result set: method, threshold and throttle.

method is the default method of pagination, single, group or infinite are allowed values, single will paginate based on a results per page (throttle value), group will paginate based on pages per results (throttle value) meaning it will try to paginate your result set into this number of pages.

threshold is the number of results before pagination is applied to the result set. For example: if you set this to 5 then only when there are more than 5 results, pagination would be applied. The default for this parameter is 100.

throttle is the maximum amount of results you want to show on a single page incase of using the default single method, when using the group method this value will refer to the ideal number of pages to show based on the results.

An example of these request parameters can be:

http://example.com/grid?threshold=5&method=group&throttle=10

In this example, the data handler will start paginating the results when there are more than 5 results. When there are less than 100 results, pagination will be created with 10 pages containing a number of results for each page based on dividing the total number of results by 10 (throttle).

Javascript Plugin

Introduction

One of our goals with Data Grid was to leave the front end HTML up to you, and avoid what most plugins do by forcing you into a specific container. We built a Javascript plugin (data-grid.js) that works together with the lodash rendering engine to allow you to easily build flexible data grids.

Requirements

Using data-grid.js requires the following:

Installation

Add jQuery, lodash, exoskeleton and data-grid.js to the <head> section of your page.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="packages/cartalyst/data-grid/js/lodash.min.js"></script>
<script src="packages/cartalyst/data-grid/js/exosjs.min.js"></script>
<script src="packages/cartalyst/data-grid/js/data-grid.js"></script>

Note Make sure you publish the assets using php artisan asset:publish cartalyst/data-grid or update the paths accordingly.

Layouts

Instead of predefined templates Data Grid finds all layouts and relates them to appropriate container using a naming pattern, layout.

Allows the creation of as many layout templates per data grid as desired.

<ul data-grid-layout="results" data-grid="foo"></ul>

The following would relate results

<script type="text/template" data-grid-template="results" data-grid="foo">

    <% _.each(response.results, function(r) { %>

        <li>
            <%= r.image %> - <%= r.name %>
        </li>

    <% }); %>

</script>

Data-grid by default has three layouts:

layouts: {
    results: {
        template: '[data-grid-template="results"]',
        layout: '[data-grid-layout="results"]'
    },
    filters: {
        template: '[data-grid-template="filters"]',
        layout: '[data-grid-layout="filters"]'
    },
    pagination: {
        template: '[data-grid-template="pagination"]',
        layout: '[data-grid-layout="pagination"]'
    }
}

Each layout is represented by key and layout options. Developers can additionally provide action. So here's the full default options for results layout:

{
    template: '[data-grid-template="results"]', // selector for our template script
    layout: '[data-grid-layout="results"]', // selector for our data placeholder
    action: 'update' // could be set as 'append' or 'prepend'
}

In case action is set to 'append', data will be appended to the layout element.

Layout can be disabled via DOM param:

<table class="table table-striped table-bordered table-hover" data-grid-layout="results" data-grid-layout-disabled data-grid="standard">

Layouts will be refreshed after results are retrieved, and they are not distinguished: hence, all layouts will be refreshed on each request and if user wants infinite results pagination, action for designated layout must be set to 'append' to prevent the existing results from being cleared before adding the new ones.

All layout and template references are cached. In case developer wants to change template or page structure, new layouts can be referenced like this:

grid.setLayout('results_updated', {
    template: '[data-grid-template="results_updated"]',
    layout: '[data-grid-layout="results_newlayout"]'
});

or update multiple layouts.

grid.setLayouts({

    'results': null, // this will remove old `results` reference

    'results_updated': {
        template: '[data-grid-template="results_updated"]',
        layout: '[data-grid-layout="results_newlayout"]'
    },

    'filters': {
        layout: '[data-grid-layout="filters_new"]' // Partially updating the existing configs (only the layout)
    }
});

The HTML

Data Grid by default requires three elements for instantiation: a results container, pagination container and a applied filters container. Each of these containers will require a corresponding template that is responsible for rendering the markup.

Note: The data-grid-template attribute is required on all templates for identification by the script.

Templates

The following lodash templates are required for every data grid and are defined using the data-grid-template attribute.

Data template Description
results Renders the results.
filters Renders applied filters.
pagination Renders pagination.

Results container

<table data-grid-layout="results" data-grid="main">

    <thead>

        <tr>

            <td>City</td>
            <td>Population</td>

        </tr>

    </thead>

    <tbody></tbody>

</table>

Results template

<script type="text/template" data-grid="main" data-grid-template="results">

    <% var results = response.results; %>

    <% if (_.isEmpty(results)) { %>
        <tr>
            <td colspan="2">No Results</td>
        </tr>
    <% } else { %>

        <% _.each(results, function(r){ %>

            <tr>

                <td><%= r.city %></td>
                <td><%= r.population %></td>

            </tr>

        <% }); %>

    <% } %>

</script>

The required data-grid attribute will allow you to create multiple Data Grids on a single page and the results data attribute will mark it as the layout container for our template. If your results container is a table, we will automatically render the template in the <tbody> element.

You might notice that the <% ... %> is the default underscore brace syntax. You can always change this behaviour by changing the template_settings on the plugin's options.

Pagination container

<ul data-grid-layout="pagination" data-grid="main"></ul>

Pagination template

<script type="text/template" data-grid="main" data-grid-template="pagination">

    <%
        // Declare some variables to avoid duplication
        var previousPage = pagination.previousPage;
        var nextPage = pagination.nextPage;

        // We'll verify here if the previous and next
        // buttons are meant to be clickable.
        var previousButton = previousPage ? 'data-grid-page="' + previousPage + '"' : 'disabled';
        var nextButton = nextPage ? 'data-grid-page="' + nextPage + '"' : 'disabled';
    %>

    <nav>
        <%- pagination.pageStart %> - <%- pagination.pageLimit %> of <%- pagination.filtered %>

        <button <%= previousButton %>>
            <i class="material-icons">chevron_left</i>
        </button>

        <button <%= nextButton %>>
            <i class="material-icons">chevron_right</i>
        </button>
    </nav>

</script>

Infinite Pagination template

<script type="text/template" data-grid="main" data-grid-template="pagination">

    <%
        // We'll verify if the load more button can be triggered or
        // not, depending if we have more results to be loaded.
        var loadMore = pagination ? 'data-grid-page="' + pagination.page + '"' : 'disabled';
    %>

    <button <%= loadMore %>>
        Load More
    </button>

</script>

Because we're setting the same data-grid attribute, the plugin will know to group it with your results container. We use the pagination data attribute to indicate it as the pagination container.

As for the other attributes, the data-grid-page attribute is where we store the current page. By default we will use page_start and page_limit in our pagination template to indicate which results are displayed on each page. This would output to 1 - 10, 11 - 20, ...

Filters container

<ul data-grid-layout="filters" data-grid="main"></ul>

Filters template

<script type="text/template" data-grid="main" data-grid-template="filters">

    <% var filters = _.reject(grid.applied_filters, function(f) {return f.type === 'live';}); %>

    <% if (_.isEmpty(filters)) { %>
        <i>There are no filters applied.</i>
    <% } else { %>

        <% _.each(filters, function(f) { %>

            <li>
                <% if (f.query.column === 'all') { %>

                    <%= f.query.value %>

                <% } else { %>

                    <%= r.query.value %> in <%= f.query.column %>

                <% } %>
            </li>

        <% }); %>
    <% } %>

</script>

We check for columns so you can display your filters in a readable manner. If your filter isn't filtering within a column it will just display the filter. If your filtering within a column we show both the filter and column.

The Javascript

Now that you have all of your templates setup, let's instantiate Data Grid. The first argument within the instantiation is the grid, this is the value of the data-grid attribute. This allows us you to have a flexible layout, and multiple Data Grids on a page. Next is the results container for the response, followed by the pagination container and finally the applied filters container.

$.datagrid(grid, options)
<script>

    $(function() {
        $.datagrid('main');
    });

</script>

After applying the plugin, you should get a nicely filled table with all of your data and pagination.

Filters

Lets go over how to set filters now that you have your Data Grid returning results. We use the data-grid-filter attribute to define filter name. The name will be used as filter's handle.

Note: Filters can be set on any html element on your page.

Term filters

Regular filters can be added on elements using a column:value pair

<button data-grid-filter="us" data-grid-query="all:USA" data-grid="main">Filter USA</button>

In case you need multiple criterias, use column1:value1; column2:value2; column3:operator:value3.

<button data-grid-filter="us2" data-grid-query="all:USA; state:California;" data-grid="main">Filter USA</button>

Range filters

Datepicker
<div class="input-group datePicker"
             data-grid="standard"
             data-grid-filter="created"
             data-grid-type="range"
             data-grid-query="created:01 Jun, 2015"
             data-grid-range="start"
             data-grid-date-format="DD MMM, YYYY"
             data-grid-label="Created At">

     <input type="text" data-format="DD MMM, YYYY" disabled class="form-control" placeholder="Start Date">

     <span class="input-group-addon" style="cursor: pointer;"><i class="fa fa-calendar"></i></span>

</div>

Optionally specify date format data-grid-date-format=":format" (empty attribute defaults to yyyy-mm-dd). If data-grid-date-format attribute is not provided, values won't be treated as date range (i.e. passed as is).

Slider
<div class="populationSlider"
     data-grid="standard"
     data-grid-filter="population"
     data-grid-type="range"
     data-grid-query="population:0:1000000"
     data-grid-label="Population">
</div>

In order to trigger slider changes, developer should add the following code:

$('.populationSlider').noUiSlider(options).on('change', function() {
    var range = $(this).val();
    $(this).data('grid-query', ['population', ':', range[0], ':', range[1]].join(''));
});
Behaviour for data-grid-query

data-grid-query can contain several kinds of data:

  • data-grid-query="column:start:end" - When change event is triggered, our query will be parsed and in case start and end is not undefined, those will be default values for our range. For this to happen, developer should omit data-grid-range="start|end" param or leave it empty, otherwise data-grid will assume that our filter consists of multiple range controls.
  • data-grid-query="column:start" and data-grid-query="column:end" followed respectively by data-grid-range="start" and data-grid-range="end" on their controls. In this case data grid will use start/end values from query param as defaults.

In case our control is not a form field element (input/select), as in our datepicker example, data-grid will try to find form fields in the control and get the value from it, or fallback to our defaults.

Filter types

Filter types determine how data-grid interacts with the filters you send it. There are 2 main filter types available out of the box.

  • term: column:operator:value (default)
  • range: :start, :end

Group filters

<select data-grid-group="country" data-grid-reset-group data-grid="foo">
    <option data-grid-reset-group="some_other_group" data-grid-reset-filter="some_other_filter">All</option>
    <option data-grid-filter="germany" data-grid-query="country:germany">Germany</option>
    <option data-grid-filter="france" data-grid-query="country:france">France</option>
    <option data-grid-filter="sweeden-norway-finland" data-grid-query="country:sweden, norway, finland">Scandinavia</option>
</select>

In this setup when user changes select from 'France' to 'Scandinavia', data-grid will reset the applied filter within the group and apply the new one - Scandinavia.

In addition to that if user clicks All, along with reseting the group data-grid will also reset filters some_other_group and some_other_filter.

Note: data-grid-group must be present for any select element that should apply filtering.

Data Grid ships with a few other things to help developers get off the ground faster. If you are looking to search within your data set, all you need to do is create a form and set the data-grid attribute and set data-grid-search. Make sure the input name is set to filter.

<form method="post" action="" accept-charset="utf-8" data-grid-search data-grid="main">

    <input name="filter" type="text" placeholder="Filter All">

    <button>Add Filter</button>

</form>

Now if you are looking for to let users filter within defined columns all you need to do is add a select menu within the form. The select name should be set to 'column' and the value of options set to the column name.

<form method="post" action="" accept-charset="utf-8" data-grid-search data-grid="main">

    <select name="column" class="input-medium">

        <option value="all">All</option>
        <option value="city">city</option>
        <option value="population">Population</option>

    </select>

    <input name="filter" type="text" placeholder="Filter All">

    <button>Add Filter</button>

</form>

Note: You can enforce strict equality on the search form using data-operator="=" on the form element.

Filter presets

Filter presets allows to use your predefined filters.

Syntax
$(function() {
    // Setup DataGrid
    var grid = $.datagrid('standard', {
        filters: {
            'mexico_large': {
                type: 'term', // Can be omitted as it's the default value
                label: 'Large Mexico cities',
                default: false, // Make this a default filter or not. Can be omitted.
                query: [
                    {
                        column: 'country',
                        value: 'Mexico',
                        operator: '=' // Can be omitted as it's the default value
                    },
                    {
                        column: 'population',
                        value: '100000',
                        operator: '>='
                    }
                ]
            }
        }
    });
});
Markup
<button data-grid-filter="mexico_large">Large mexican cities</button>

data-grid-label and data-grid-filter-default attributes can be set up in markup, but config values will prevail.

Filter by relations

Data grid supports filtering by eloquent relations. A filter by relation is applied using the form "column..table:value"

<ul class="dropdown-menu" role="tags">
    @foreach ($tags as $tag)
    <li><a href="#" data-grid-filter="tag:{{{ $tag }}}" data-grid-query="tags..name:{{{ $tag }}}" data-grid-label="{{{ $tag }}}">{{{ $tag }}}</a></li>
    @endforeach
</ul>

Note: When you filter by a relation a whereHas call is invoked on the DatabaseHandler which performs a regular array search on the collection handler.

Other filter options

Grouping filters under one data-grid attribute

You can omit the data-grid attribute from filter elements if the parent element already has it set.

<div data-grid="main">

    <button data-grid-filter="us" data-grid-query="country:us">United States of America</button>
    <button data-grid-filter="ca" data-grid-query="country:ca">Canada</button>
    <button data-grid-filter="uk" data-grid-query="country:uk">United Kingdom</button>

</div>

Reset

  • data-grid-reset - clears all filters.
  • data-grid-reset-group=":name" - resets all filters within a group. (:name optional)
  • data-grid-reset-filter=":name" - resets single filter. (:name optional)

If you want to give your users a simple way to reset Data Grid, just create a button, set the attributes data-grid and data-reset and you're done.

<button data-grid-reset data-grid="main">Reset</button>
Reset all other filters

You can add a data-grid-reset attribute to any filter element to force clearing other filters before applying the current filter.

<button data=grid-filter="us" data-grid-query="country:us" data-grid-reset data-grid="main">USA</button>

This will clear any already applied filters before applying the us filter.

Reset filters based on a group

You can add a data-grid-reset-group attribute on a parent element of all filters you want cleared, it acts as grouped filters that force clear all filters belogning to this group before applying a new one.

<div data-grid="main" data-grid-group="ids" data-grid-reset-group>

    <button data-grid-filter="id1" data-grid-query="id:1">ID 1</button>
    <button data-grid-filter="id2" data-grid-query="id:2">ID 2</button>
    <button data-grid-filter="id3" data-grid-query="id:3">ID 3</button>

</div>

This will clear only filters that are part of this group while leaving other filters untouched.

Sorts

<a href="#" data-grid-sort="city:asc" data-grid="main">Sort By City ASC</a>

This will sort the data grid by city in a ascending order.

<a href="#" data-grid-sort="city:desc" data-grid="main">Sort By City DESC</a>

This will sort the data grid by city in a descending order.

Multi-column sort

You can sort you results by multiple columns by clicking a column with holding down the Shift key.
This feature can be disabled by setting sorting.multisort to false.

Set sort on filter

Additionally you can set you sorts on a filter. This way when user clicks the filter, it will set up your sort.

<a href="#" data-grid="main" data-grid-filter="us" data-grid-query="country:us" data-grid-sort="subdivision:asc; population:desc">US</a>

Labels

From time to time, when using filters and sorts you will run into issues when your column names have underscores or something of that nature. Because of this we've created the data-grid-label attribute to help you rewrite this to achieve a better user experience. The data-grid-label should contain the label you want to use for applied filter.

<a href="#" data-grid-filter="us-washington" data-grid-query="country:us; subdivision:washington; population:<:5000" data-grid-label="Small cities in Washington">Washington, United States < 5000</a>

Options

You can specify plugin options by adding a second object parameter to your plugin instantiation.

<script>
    $(function() {
        $.datagrid('main', {
            source: 'http://example.com/api/v1',
            sort: {
                column: 'city',
                direction: 'desc'
            },
            ...
        });
    });
</script>

Available options with defaults:

{
    source: null,

    pagination: {
        method: 'single',
        threshold: null,
        throttle: null,
        scroll: null,
        infiniteScroll: false,
        scrollOffset: undefined
    },

    cssClasses: {
        ascClass: 'asc',
        descClass: 'desc',
        appliedFilter: 'selected',
    },

    sorting: {
        column: undefined,
        direction: undefined,
        multicolumn: true,
        delimiter: ','
    },

    delimiter: {
        query: ';',
        expression: ':'
    },

    templateSettings: {
        evaluate: /<%([\s\S]+?)%>/g,
        interpolate: /<%=([\s\S]+?)%>/g,
        escape: /<%-([\s\S]+?)%>/g,
    },

    filters: {},

    search: {
        live: true,
        timeout: 600
    },

    url: {
        hash: true,
        semantic: false,
        base: '',
    },

    loader: {
        element: undefined,
        showEffect: 'fadeIn',
        hideEffect: 'fadeOut',
        duration: 200,
    },

    formats: {
        timestamp: 'YYYY-MM-DD HH:mm:ss',
        serverDate: 'YYYY-MM-DD',
        clientDate: 'MMM DD, YYYY',
    },

    callback: undefined
}

Below is a list with all of the available options.

General options

Option Type Description
source string The API endpoint URI.
pagination object The pagination settings
cssClasses object The css classes used for asc/desc sorts and applied filters.
sorting object The sort settings.
delimiter object Delimiter settings.
layouts object Layout settings.
templateSettings object Changes the surrounding braces. Data Grid's default is set to <% ... %>.
filters object Filter presets.
search object Set the threshold for the live search feature. (Time after last keystroke before search starts)
hash object URL options.
loader object Settings for the loader shown while the ajax request is made.
callback function This parameter you can pass a function that will run every time a filter is added, or a sort is applied. This function receives one argument, and gives you access most values within Data Grid.
events object This parameter you can pass an object with events and functions to run custom logic after specific actions are called.

Pagination options

Option Type Description
method string The pagination method, accepts single, group or infinite.
threshold integer Minimum amount of results before pagination is applied.
throttle integer The maximum amount of results on a single page. Overrides dividend.
scroll mixed Set an element selector to scroll to or a function to apply manual scrolling.
infiniteScroll bool Enables infinite scroll.
scrollOffset number Set an offset when to trigger infinite scroll.

CSS Classes

Option Type Description
ascClass string Set a css class for ascending order.
descClass string Set a css class for descending order.
appliedFilter string The class that should be added to applied filter elements.

Sorting options

Option Type Description
column string Set a default sort column.
direction string Set a default sort direction.
multicolumn string Indicates whether multicolumn filtering should be supported.
delimiter string Set a multi-column sort delimiter for url. , by default

Delimiter options

Option Type Description
query string Set a query delimiter. ';' is the default.
expression string Set an expression delimiter. ':' is the default.

Search options

Option Type Description
live bool Live search.
timeout number Timeout before applying live search on key press.

Url options

Option Type Description
hash bool Enables handling hash urls.
semantic bool Enables using semantic user-friendly urls instead of '#'.
base string Distinguisher for base url and data-grid params.

Default url looks like this:

http://demo.cartalyst.com/data-grid/standard#population/throttle:20

Enabling semantic url will give you this:

http://demo.cartalyst.com/data-grid/standard/population/throttle:20

where /data-grid/standard should be set as your url options base.

Note: Make sure to set up your back end router properly, as the data-grid doesn't handle it.
E.g.: Route::get('semantic{hash}', 'MyController@grid')->where('hash', '(.*)?');

Loader options

Option Type Description
element string Your loader object selector. ie. .loader
showEffect string Sets the loader show effect. ie. fadeIn
hideEffect string Sets the loader hide effect. ie. fadeOut
duration number Effect duration.

Events

Below is a list with all of the events that are fired throughout the lifecycle.

Event Description
applying Fired before a filter is applied.
applied Fired after a filter has been applied.
removing Fired before a filter is removed.
removed Fired after a filter has been removed.
removing_group Fired before a filter group is removed.
removed_group Fired after a filter group has been removed.
sorting Fired before sorting is applied.
sorted Fired after sorting has been applied.
fetching Fired before triggering the ajax fetch request.
fetched Fired after a successful ajax fetch request.
switching Fired before the page changes.
switched Fired after the page has changed.
reset Fired after the grid is reset.

Example

Each event brings the context on what exactly has happened.

Binding chained callbacks
var grid = $.datagrid(‘standard’, options)
    .on(‘dg:applying’, function(filter) {
        console.log(this, filter);
    });

or

var grid = $.datagrid(‘standard’, options)
    .on({
        dg:applying’: function(filter) {
            console.log(this, filter);
        },
        dg:applied’: function(filter) {
            console.log(this, filter);
        }
    });
Event callbacks in options
var grid = $.datagrid('standard', {
    events: {
        'dg:applying': function(filter) {
            console.log(this, filter);
        }
    }
});
Callback arguments
  • this - is a dg instance
  • filter is js object with all information regarding filter:
{
    name: country:canada”,
    type: term
    label: Canada”,
    default: false,
    query: [{column: country”, value: Canada”}]
}

Extending

This plugin was built with extensibility in mind,

You can override or extend any method using the following syntax.

$.datagrid.prototype.{method} = function ({params}) {

    // Your logic

};

Hooking into an existing method

You can hook into existing methods to apply custom logic before the method is invoked.

var original_method = $.datagrid.prototype.getThreshold;

$.datagrid.prototype.getThreshold = function () {

    // Your custom logic
    return original_method.call(this);

};

Overriding an existing method

You can override existing methods.

$.datagrid.prototype.getThreshold = function () {
    // Your custom logic
};

Extending data grid

You can extend data grid and add new methods that are then callable on data grid.

$.datagrid.prototype.yourNewMethod = function () {
    // Your custom logic
    return this.pagination.page_index - 1;
};

Integration

Data-grid is framework agnostic, which means its core is clean, native php.
All framework specific features are separated to its own implementation packages, so integrating it with your framework of choice is incredibly easy.

Laravel 9

The Data Grid package has optional support for Laravel 9 and it comes bundled with a Service Provider and a Facade for easy integration.

To install Laravel bridge package, add the following requirements to your composer.json:

"cartalyst/data-grid-laravel": "^5.0"

You don't have to add cartalyst/data-grid requirement, the bridge will ensure all the requirements for you.

Run composer update and after installing the package, open your Laravel config file located at config/app.php and add the following lines.

In the $providers array add the following service provider for this package.

Cartalyst\DataGrid\Laravel\DataGridServiceProvider::class,

In the $aliases array add the following facade for this package.

'DataGrid' => Cartalyst\DataGrid\Laravel\Facades\DataGrid::class,

Resources

Configuration

To publish the configuration file run the following on your terminal:

php artisan vendor:publish --tag="cartalyst:data-grid.config"

This will publish the config file to config/cartalyst/data-grid/config.php where you can modify the package configuration.

Assets

To publish the assets run the following on your terminal:

php artisan vendor:publish --tag="cartalyst:data-grid.assets"

This will publish the assets to the following path public/assets/vendor/cartalyst/data-grid/*.

Database Handler

The bridge package comes with a DatabaseHandler, allowing you to work with your Eloquent models or any illuminate/database components.

Usage
use Cartalyst\DataGrid\Laravel\DataHandlers\DatabaseHandler;

$handler = new DatabaseHandler($data, $settings);
$dataGrid = DataGrid::make($handler);
Settings

On top of available options, data-grid-laravel additionally supports the following options:

Option Type Default Description
filters array Array of callables to handle custom filters.
sorts array Array of callables to handle custom sorts.
Custom filters

Custom filters allow you to adjust the default behavior for column filters.

use Cartalyst\DataGrid\Laravel\DataHandlers\DatabaseHandler;

$settings = [
    'columns' => [
        'title',
        'age',
    ],
    'filters' => [
        'active' => function($query, $operator, $value) {
            $value = (bool)$value;

            // Because there could be 'pending', 'expired' or whatever
            $operator = ($value) ? '=' : '!=';

            $query->where('is_active', $value);
            $query->where('status', $operator, 'active');
        },
    ]
];

$handler = new DatabaseHandler($data, $settings);
$dataGrid = DataGrid::make($handler);
Custom sorts

Custom sorts allow you to adjust the default behavior for sorting.

use Cartalyst\DataGrid\Laravel\DataHandlers\DatabaseHandler;

$settings = [
    'columns' => [
        'title',
        'age',
    ],
    'sorts' => [
        'popular' => function(Builder $query, $direction) {
            $query->orderBy('views', $direction);
        }
    ]
];

$handler = new DatabaseHandler($data, $settings);
$dataGrid = DataGrid::make($handler);

Export

DataGrid Export is a package that provides support for exporting your result sets to any other data structure.

"cartalyst/data-grid-export": "^5.0"

You don't have to add cartalyst/data-grid requirement, the package will ensure all the requirements for you.

Export Provider

ExportProvider simply extends the default RequestProvider and adds behavior for download requests.

Usage
use Cartalyst\DataGrid\Export\Providers\ExportProvider;

$handler = new DatabaseHandler($data, $settings);
$provider = new ExportProvider();

$dataGrid = DataGrid::make($handler, $provider);
Settings

Data-grid Export supports the following settings, which you can pass to the data handler:

Option Type Default Description
pdf_view string cartalyst/data-grid::pdf Pdf view that renders the results for pdf download.
pdf_filename string data-grid Pdf filename for pdf download.
json_options int null Json options ex. JSON_PRETTY_PRINT for json download.
json_filename string data-grid Json filename for json download.
csv_delimiter string ',' Csv delimiter for csv download
csv_filename string data-grid Csv filename for csv download.
csv_parser function null Csv parser, define your own parser for csv download.
max_results int null Maximum results for downloads.
Export Driver

ExportProvider supports the following drivers by default:

  • Cartalyst\DataGrid\Export\ExportDrivers\CsvDriver
  • Cartalyst\DataGrid\Export\ExportDrivers\JsonDriver
  • Cartalyst\DataGrid\Export\ExportDrivers\PdfDriver

You can customize the existing export drivers or create your own.

class MyPdfDriver extends PdfDriver {
    // E.g. customize your driver to use mPDF instead of dompdf
}

Then use helper method to add your own driver. It will replace any existing driver references for the download type:

ExportProvider::addDriver('pdf', new MyPdfDriver());

You wont find fancy lifestyle graphics and marketing bravado here. Just cold... hard... code...

Code Well, Rock On!
Processing Payment...