-
Notifications
You must be signed in to change notification settings - Fork 116
Frontend
The most easy way to start with datagrid frontend is using the generator.
rails generate datagrid:scaffold <model in plural> # e.g. users
This will build controller, view, route and add built-in CSS.
Datagrid includes helpers and form builder for easy front end generation. If you need to build full featured custom GUI you should create your templates manually with the help of Columns API.
Grids in most cases implement index
of a Rails REST resources. It is the only one action you need to display grid:
resources :models, :only => [:index]
In this case GET
method should be always used in a form. And controller will look damn simple:
class ModelsController < ApplicationController
def index
@grid = ModelsGrid.new(params[:my_report]) do |scope|
scope.page(params[:page]) # See pagination section
end
end
end
Additional scoping conditions can be applied in case there is visibility limitation based on current user or any other context:
ModelsGrid.new(params[:my_report]) do |scope|
scope.where(owner_id: current_user.id).page(params[:page])
end
To pass an object to a grid instance, simply define it as accessible attribute:
class ModelsGrid
...
attr_accessor :current_user
...
end
The attribute will be automatically assigned when you merge it to parameters in constructor:
ModelsGrid.new(params[:models_grid].merge(current_user: current_user))
Use datagrid built-in partial:
= datagrid_form_for @grid, :url => report_path, :other_form_for_option => value
datagrid_form_for
supports the same options as Rails form_for
helper.
In order to create a form you can use all set of rails built-in tools. In addition Datagrid provides you magic helper to generate input/select for corresponding filter type:
(haml for readability)
- form_for UserGrid.new, :method => :get, :url => users_path do |f|
%div
= f.datagrid_label :name
= f.datagrid_filter :name # => <input name="grid[name]" type="text"/>
%div
= f.datagrid_label :category_id
= f.datagrid_filter :category_id # => <select name="grid[category_id]">....</select>
The easiest way to create a report form:
- form_for @report, :method => :get, :url => users_path do |f|
- @report.filters.each do |filter|
%div
= f.datagrid_label filter
= f.datagrid_filter filter
= f.submit
If datagrid_filter
doesn't provide enough flexibility, default rails helpers can do the job:
%div
= f.label :name
= f.text_field :name
See also localization section of Filters
There is a simple helper set of helpers that allows you display report. The most common way of doing it is (require any pagination gem, will_paginate gem is used as an example):
%div== Total #{@grid.assets.total}
= datagrid_table(@report)
= will_paginate @report.assets
Supported options:
-
:html
- hash of attributes for<table>
tag -
:order
- If false do not generate ordering controlls. Default:true
. -
:columns
- Array of column names to display. Used in case when same grid class is used in different places and needs different columns. Default: all defined columns.
This will create generic table from paginated assets
with all defined columns and sorting controlls.
See also Localization section of Columns
It has only one pagination-sensitive helper: datagrid_table
.
In order to add pagination, add the following in your controllers:
# Kaminari
@grid = MyGrid.new(params[:grid]) do |scope|
scope.page(params[:page]).per(10)
end
# WillPaginate
@grid = MyGrid.new(params[:grid]) do |scope|
scope.page(params[:page]).per_page(10)
end
# Pagy
@grid = MyGrid.new(params[:grid])
@pagy, @records = pagy(@grid.assets)
And then render paginated collection:
# WillPaginate, Kaminari
<%= datagrid_table(@grid, options) %>
# Pagy
<%= datagrid_table(@grid, @records, options) %>
You are able to build table almost from scratch using the instance API of Datagrid object like:
grid.columns # => Array of columns
grid.row_for(model) # => Array of column values for given object
grid.scope # => Scope defined in grid
grid.hash_for(model) # => Hash with column names as keys and column values for given model as values
More info here: http://rubydoc.info/gems/datagrid/Datagrid/Columns/InstanceMethods
Additional Frontend helpers are also available:
datagrid_header(grid) # Renders HTML table header for given grid instance using columns defined in it.
datagrid_order_for(grid, column_name) # Renders ordering controls for the given column name.
datagrid_row(grid, asset) # Provides access to datagrid columns data.
datagrid_rows(grid, assets) # Renders HTML table rows using given grid definition using columns defined in it.
More info here: http://rubydoc.info/gems/datagrid/Datagrid/Helper
In order to support it extend your controller to handle csv response format:
class UsersController < ApplicationController
def index
@grid = UsersGrid.new(params[:users_grid])
respond_to do |f|
f.html do
@grid.scope {|scope| scope.page(params[:page]) }
end
f.csv do
send_data @grid.to_csv,
type: "text/csv",
disposition: 'inline',
filename: "grid-#{Time.now.to_s}.csv"
end
end
end
end
Now place the button in the interface like:
link_to "Get CSV", url_for(format: 'csv', users_grid: params[:users_grid])
Datagrid provides a trivial way of asyncronous loading of data into datagrid table.
Put the following to your controller:
if request.xhr?
render json: {table: view_context.datagrid_table(@grid)}
end
Modify the form to perform AJAX load submit and data load:
= datagrid_form_for @grid, html: {class: 'js-datagrid-form'}
.js-datagrid-table
= datagrid_table @grid
.js-pagination
= paginate @grid.assets
:javascript
$('.js-datagrid-form').submit(function(event) {
event.preventDefault();
$.get($(this).attr("action"), $(this).serialize(), function (data) {
$('.js-datagrid-table').html(data.table);
});
});
If You need serious customisation of datagrid helpers and all customisation options doesn't help, you can customise datagrid internal views by running:
rake datagrid:copy_partials
This will create the following files in your rails root directory:
app/views/datagrid/
├── _enum_checkboxes.html.erb
├── _form.html.erb
├── _head.html.erb
├── _order_for.html.erb
├── _range_filter.html.erb
├── _row.html.erb
└── _table.html.erb
Now You are able to customize whatever You want.
You are able to add a custom options to Datagrid columns and filters and implement their support on frontend.
For example: Columns need to have description
beside header
that only appears on mouse over on column header.
column(
:aov, header: 'AOV',
description: 'Average order value: sum of orders subtotal divided by their count'
) do |category|
category.orders.sum(:subtotal) / category.orders.count
end
:description
is not a built in option of Datagrid, but it can be your own. In order to implement it modify the column header partial app/views/datagrid/_header.html.erb
to use it:
%tr
- grid.html_columns(*options[:columns]).each do |column|
%th{class: datagrid_column_classes(grid, column)}
= column.header
+ - if column.options[:description]
+ %a{data: {toggle: 'tooltip', title: column.options[:description]}}
+ %i.icon-question-sign
- if column.order && options[:order]
= datagrid_order_for(grid, column, options)
In this description tooltip will work with UI you want and your favourite JavaScript library.
Same technique can be applied to filters by calling filter.options
in corresponding partials.
If you would like to attach a different html class to each row making it stylable with CSS, you add it this configuration option by modifying built-in partial _row.html.erb
:
-<tr>
+<tr class="<%= grid.respond_to?(:row_class) ? grid.row_class(asset) : "" %>">
<% grid.html_columns(*options[:columns]).each do |column| %>
<td class="<%= datagrid_column_classes(grid, column) %>"><%= datagrid_value(grid, column, asset) %></td>
<% end %>
It will make it possible to define column HTML class in each grid like this:
class IssuesGrid
include Datagrid
scope { Issue }
def row_class(issue)
case issue.status
when "fixed" then "green"
when "rejected" then "red"
else "blue"
end
end
end
Modify _form.html.erb
:
- <%= f.datagrid_filter filter %>
+ <%= f.datagrid_filter filter, filter.options[:input_options] %>
Now you can specify :input_options
for any filter definition:
filter(:username, :string, input_options: {
maxlength: 10, placeholder: 'Specify Login Name'
})
Here are all datagrid custom localization keys that you can overwrite at application level:
https://github.com/bogdan/datagrid/blob/master/lib/datagrid/locale/en.yml