veracross/data-table

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# DataTable

[![veracross/data-table](https://circleci.com/gh/veracross/data-table.svg?style=shield)](https://app.circleci.com/pipelines/github/veracross/data-table)
[![Code Climate](https://codeclimate.com/github/veracross/data-table.svg)](https://codeclimate.com/github/veracross/data-table)

DataTable renders collections (an array of hashes or ActiveRecord models) as HTML tables.

## Install
```ruby
gem install data-table
```

or, in your Gemfile

```ruby
gem 'data-table'
```

### Basic Usage

the normal usage is to call the `DataTable.render()` method and pass it a collection.  The method also takes a block which can be used to configure the table.  The column method takes a symbol for the first parameter.  If the symbol matches a key in the @collection, then that value is printed in the cell.

```ruby
DataTable.render(@collection) do |t|
  t.column :column_1, "Title"
  t.column :column_2, "Title 2"
end
```

### Custom Cell Renderer

Sometimes you want to use Ruby code to customize the value for a cell.  This can be done by passing a block to the .column method

```ruby
DataTable.render(@collection) do |t|
   t.column :column_id, "Title" do |value, row, row_index, column, column_index|
     "The value is: #{value}"
   end
end
```

You don't need to pass in all of the block parameters; just the ones up to the one you need.

**Tip** The column_id doesn't need to be an actual key in the collection.  You can just make up an arbitrary column id and use the block renderer to customize the value for a column.


### All Table Configuration Options

    id: the html id
    title: the title of the data table
    subtitle: the subtitle of the data table
    css_class: an extra css class to get applied to the table
    empty_text: the text to display of the collection is empty
    display_header => false: hide the column headers for the data table
    alternate_rows => false: turn off alternating of row css classes
    alternate_cols => true: turn on alternating of column classes, defaults to false

### Totals

It is possible to setup totals & subtotals. Total columns take the name of the column that should be totaled. It is also possible to specify multiple total and subtotal columns.

They also take a default aggregate function name and/or a block.
* If only a default function is given, then it is used to calculate the total
* If only a block is given then only it is used to calculated the total
* If both a block and a function are given then the default aggregate function is called first then its result is passed into the block for further processing.

```ruby
DataTable.render(@collection) do |t|
  t.column :column_1, "Title"
  t.column :column_2, "Title 2"
  t.column :column_3, "Title 3"

  # Use a default function and no block.
  t.total :column_1, 0, :sum

  # Pass only a block and an index
  t.total :column_2, 1, do |values|
    # custom methods here
  end

  # Pass a default function and a block
  t.total(:column_3, 2, :sum) do |aggregate_total|
    format_money(aggregate_total)
  end

end
```

Possible default functions: `:sum`, `:avg`, `:min`, `:max`


### Sub Totals

SubTotals work in a similar way to Totals.  The main difference is that you need to call group_by to specify the different subtotal groupings.

When configuring more than one subtotal column the index parameter is required

```ruby
DataTable.render(@collection) do |t|
  t.column :column_1, "Title"
  t.column :column_2, "Title 2"
  t.column :column_3, "Title 3"
  t.column :column_4, "Title 4"

  t.group_by :column_1

  t.subtotal :column_2, 0, :sum
  t.subtotal :column_3, 1, :max
end
```
It is possible to use `group_by` on its own without subtotaling.

### Multiple Groups and Sub Totals

It is also possible to combine multiple `group_by` with multiple `subtotal`. In this
scenario you must specify a `level` for each group by passing an integer value.
When only specifying a group you may omit `level`.

```ruby
DataTable.render(@collection) do |t|
  t.column :column_1, "Title"
  t.column :column_2, "Title 2"
  t.column :column_3, "Title 3"

  t.group_by :column_1, 0
  t.group_by :column_2, 1

  t.subtotal :column_3, 0, :sum
  t.subtotal :column_3, 0, :sum
end
```

You can also combine subtotals & totals in the same table.

## Credits
Nearly all of the code for this was written by @smerickson, and later gemified by @sixfeetover.