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 7.3+ 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
, orgrouped
. - 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
andtransformer
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": "^7.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 runningcomposer 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 thecolumns
settings, it will returnnull
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:
- lodash v3.10.0 or later
- exoskeleton v0.6.3 or later
- jQuery v1.9.1 or later
- Moment.js v2.6.0 or later Optional (filter using custom date formats)
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
andend
is not undefined, those will be default values for our range. For this to happen, developer should omitdata-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"
anddata-grid-query="column:end"
followed respectively bydata-grid-range="start"
anddata-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.
Search
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 theform
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 instancefilter
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 8
The Data Grid package has optional support for Laravel 8 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": "^4.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": "^4.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());