Module: Datagrid::Helper
- Defined in:
- lib/datagrid/helper.rb
Overview
Datagrid Frontend Guide
Description
The easiest way to start with Datagrid frontend is by using the generator:
rails generate datagrid:scaffold users
This command builds the controller, view, route, and adds built-in CSS.
Datagrid includes helpers and a form builder for easy frontend generation. If you need a fully-featured custom GUI, create your templates manually with the help of the Columns API.
Controller and Routing
Grids usually implement the index
action of a Rails REST resource. Here's an example:
resources :models, only: [:index]
Use the GET
method in the form, and the controller becomes straightforward:
class ModelsController < ApplicationController
def index
@grid = ModelsGrid.new(params[:my_report]) do |scope|
scope.page(params[:page]) # See pagination section
end
end
end
To apply additional scoping conditions, such as visibility based on the current user:
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, define it as an accessible attribute:
class ModelsGrid
attr_accessor :current_user
end
Then pass it when initializing the grid:
ModelsGrid.new(params[:models_grid].merge(current_user: current_user))
Form Builder
Basic Method
Use the built-in partial:
= datagrid_form_with model: @grid, url: report_path, other_form_for_option: value
#datagrid_form_with supports the same options as Rails form_with
.
Advanced Method
You can use Rails built-in tools to create a form. Additionally, Datagrid provides helpers to generate input/select elements for filters:
- form_with model: 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>
For more flexibility, use Rails default helpers:
%div
= f.label :name
= f.text_field :name
See the localization section of Filters.
Datagrid Table
Use the helper to display a report:
%div== Total #{@grid.assets.total}
= datagrid_table(@report)
= will_paginate @report.assets
Options:
:html
- Attributes for the<table>
tag.:order
- Set tofalse
to disable ordering controls (default:true
).:columns
- Specify an array of column names to display.
Pagination
Datagrid is abstracted from pagination but integrates seamlessly with tools like Kaminari, WillPaginate, or Pagy:
# 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)
Render the paginated collection:
# WillPaginate or Kaminari
<%= datagrid_table(@grid, options) %>
# Pagy
<%= datagrid_table(@grid, @records, options) %>
CSV Export
Add CSV support to your controller:
class UsersController < ApplicationController
def index
@grid = UsersGrid.new(params[:users_grid])
respond_to do |f|
f.html { @grid.scope { |scope| scope.page(params[:page]) } }
f.csv do
send_data @grid.to_csv, type: "text/csv", disposition: 'inline', filename: "grid-#{Time.now.to_s}.csv"
end
end
end
end
Add a button in your interface:
link_to "Get CSV", url_for(format: 'csv', users_grid: params[:users_grid])
AJAX
Datagrid supports asynchronous data loading. Add this to your controller:
if request.xhr?
render json: {table: view_context.datagrid_table(@grid)}
end
Modify the form for AJAX:
= datagrid_form_with model: @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);
});
});
Modifying Built-In Partials
To customize Datagrid views:
rake datagrid:copy_partials
This creates files in app/views/datagrid/
, which you can modify to suit your needs:
app/views/datagrid/
├── _enum_checkboxes.html.erb # datagrid_filter for filter(name, :enum, checkboxes: true)
├── _form.html.erb # datagrid_form_with
├── _head.html.erb # datagrid_header
├── _range_filter.html.erb # datagrid_filter for filter(name, type, range: true)
├── _row.html.erb # datagrid_rows/datagrid_rows
└── _table.html.erb # datagrid_table
Custom Options
You can add custom options to Datagrid columns and filters and implement their support on the frontend.
For example, you might want to add a description
option to a column that appears as a tooltip on mouseover.
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
The :description
option is not built into Datagrid, but you can implement it
by adding the following to partial app/views/datagrid/_header.html.erb
:
<% if column.options[:description] %>
<a data-toggle="tooltip" title="<%= column.options[:description] %>">
<i class="icon-question-sign"></i>
</a>
<% end %>
This modification allows the :description
tooltip to work with your chosen UI and JavaScript library.
The same technique can be applied to filters by calling filter.options
in corresponding partials.
Highlight Rows
To add custom HTML classes to each row for styling, modify the _row.html.erb
partial:
-<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 %>
This allows you to define a custom row_class
method in your grid class, like this:
class IssuesGrid < ApplicationGrid
scope { Issue }
def row_class(issue)
case issue.status
when "fixed" then "green"
when "rejected" then "red"
else "blue"
end
end
end
Localization
You can overwrite Datagrid’s custom localization keys at the application level. See the localization keys here:
https://github.com/bogdan/datagrid/blob/master/lib/datagrid/locale/en.yml
Defined Under Namespace
Classes: HtmlRow
Instance Method Summary collapse
-
#datagrid_form_for(grid, options = {}) ⇒ String
deprecated
Deprecated.
Use #datagrid_form_with instead.
-
#datagrid_form_with(**options) ⇒ String
Renders HTML for grid with all filters inputs and labels defined in it.
-
#datagrid_header(grid, opts = :__unspecified__, **options) ⇒ String
Renders HTML table header for given grid instance using columns defined in it.
-
#datagrid_order_for(grid, column, options = {}) ⇒ String
deprecated
Deprecated.
Put necessary code inline inside datagrid/head partial. See built-in partial for example.
-
#datagrid_order_path(grid, column, descending) ⇒ String
Generates an ascending or descending order url for the given column.
-
#datagrid_row(grid, asset, **options, &block) ⇒ Datagrid::Helper::HtmlRow, String
Provides access to datagrid columns data.
-
#datagrid_rows(grid, assets = grid.assets, **options, &block) ⇒ String
Renders HTML table rows using given grid definition using columns defined in it.
-
#datagrid_table(grid, assets = grid.assets, **options) ⇒ String
Renders html table with columns defined in grid class.
-
#datagrid_value(grid, column, model) ⇒ Object
Individual cell value from the given grid, column name and model.
Instance Method Details
#datagrid_form_for(grid, options = {}) ⇒ String
Use #datagrid_form_with instead.
Renders HTML for grid with all filters inputs and labels defined in it
Supported options:
- :partials - Path for form partial lookup. Default: 'datagrid'.
- All options supported by Rails form_with helper
389 390 391 392 393 394 395 396 397 398 399 400 401 |
# File 'lib/datagrid/helper.rb', line 389 def datagrid_form_for(grid, = {}) Datagrid::Utils.warn_once("datagrid_form_for is deprecated if favor of datagrid_form_with.") _render_partial( "form", [:partials], grid: grid, options: { method: :get, as: grid.param_name, local: true, **, }, ) end |
#datagrid_form_with(**options) ⇒ String
Renders HTML for grid with all filters inputs and labels defined in it
369 370 371 372 373 374 375 376 |
# File 'lib/datagrid/helper.rb', line 369 def datagrid_form_with(**) raise ArgumentError, "datagrid_form_with block argument is invalid. Use form_with instead." if block_given? grid = [:model] raise ArgumentError, "Grid has no available filters" if grid&.filters&.empty? _render_partial("form", [:partials], { grid: [:model], options: }) end |
#datagrid_header(grid, opts = :__unspecified__, **options) ⇒ String
Renders HTML table header for given grid instance using columns defined in it
307 308 309 310 311 312 313 314 315 316 |
# File 'lib/datagrid/helper.rb', line 307 def datagrid_header(grid, opts = :__unspecified__, **) unless opts == :__unspecified__ Datagrid::Utils.warn_once("datagrid_header now requires ** operator when passing options.") .reverse_merge!(opts) end [:order] = true unless .key?(:order) _render_partial("head", [:partials], { grid: grid, options: },) end |
#datagrid_order_for(grid, column, options = {}) ⇒ String
Put necessary code inline inside datagrid/head partial. See built-in partial for example.
Returns renders ordering controls for the given column name.
351 352 353 354 355 356 357 358 359 |
# File 'lib/datagrid/helper.rb', line 351 def datagrid_order_for(grid, column, = {}) Datagrid::Utils.warn_once(<<~MSG) datagrid_order_for is deprecated. Put necessary code inline inside datagrid/head partial. See built-in partial for example. MSG _render_partial("order_for", [:partials], { grid: grid, column: column },) end |
#datagrid_order_path(grid, column, descending) ⇒ String
Generates an ascending or descending order url for the given column
434 435 436 437 438 439 440 441 |
# File 'lib/datagrid/helper.rb', line 434 def datagrid_order_path(grid, column, descending) column = grid.column_by_name(column) query = request&.query_parameters || {} ActionDispatch::Http::URL.path_for( path: request&.path || "/", params: query.merge(grid.query_params(order: column.name, descending: descending)), ) end |
#datagrid_row(grid, asset, **options, &block) ⇒ Datagrid::Helper::HtmlRow, String
Provides access to datagrid columns data. Used in case you want to build html table completelly manually
423 424 425 426 427 |
# File 'lib/datagrid/helper.rb', line 423 def datagrid_row(grid, asset, **, &block) Datagrid::Helper::HtmlRow.new(self, grid, asset, ).tap do |row| return capture(row, &block) if block_given? end end |
#datagrid_rows(grid, assets = grid.assets, **options, &block) ⇒ String
Renders HTML table rows using given grid definition using columns defined in it. Allows to provide a custom layout for each for in place with a block
336 337 338 339 340 341 342 |
# File 'lib/datagrid/helper.rb', line 336 def datagrid_rows(grid, assets = grid.assets, **, &block) safe_join( assets.map do |asset| datagrid_row(grid, asset, **, &block) end.to_a, ) end |
#datagrid_table(grid, assets = grid.assets, **options) ⇒ String
Renders html table with columns defined in grid class. In the most common used you need to pass paginated collection to datagrid table because datagrid do not have pagination compatibilities:
283 284 285 286 287 288 289 290 291 292 |
# File 'lib/datagrid/helper.rb', line 283 def datagrid_table(grid, assets = grid.assets, **) _render_partial( "table", [:partials], { grid: grid, options: , assets: assets, }, ) end |
#datagrid_value(grid, column, model) ⇒ Object
Returns individual cell value from the given grid, column name and model.
255 256 257 258 259 |
# File 'lib/datagrid/helper.rb', line 255 def datagrid_value(grid, column, model) column = grid.column_by_name(column) if column.is_a?(String) || column.is_a?(Symbol) grid.html_value(column, self, model) end |