ember-powerful-table
v0.0.5
Published
Easy way to dinamically generate tables.
Downloads
5
Readme
ember-powerful-table
Easy way to dinamically generate tables.
Usage
It's simple: just create a settings object and pass it to powerful-table
component.
Let's ignore styles for while, we'll talk about it at the end of this document.
Important now are the features!
Basic
Configure the columns
and rows
.
// controllers/test.js
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{ title: 'Name', fields: 'name' },
{ title: 'Lastname', fields: 'lastname' },
],
rows: [
{ name: 'Bruno', lastname: 'Salgado' },
{ name: 'Pri', lastname: 'Lopes' },
],
},
});
Send the settings to powerful-table
component.
{{!-- templates/test.hbs --}}
{{powerful-table table=myTableSettings}}
Result
|Setting|Type|Description|
|-|-|-|
|columns
|array of objects
|the columns the table will show|
|columns[].title
|string
|text on header|
|columns[].fields
|string
or array of strings
|corresponding information on rows|
|rows
|array of objects
|data to fill the table|
Asynchronous Rows
Configure rows
as a promise.
export default Ember.Controller.extend({
myTableSettings: Ember.computed(function(){
return {
columns: [
{ title: 'Name', fields: 'name' },
{ title: 'Lastname', fields: 'lastname' },
],
rows: this.loadPeople(),
}
}),
loadPeople() {
return new Ember.RSVP.Promise((resolve, reject) => {
Ember.run.later(() => {
resolve([
{ name: 'Gustavo', lastname: 'Salgado' },
{ name: 'Miguel', lastname: 'Salgado' },
]);
}, 3000);
});
},
});
|Setting|Type|Description|
|-|-|-|
|rows
|promise
|wait the promise resolve to fill the table|
Formatting Values
The original values on rows
can be formatted before showed using columns[].valueFormat
.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{ title: 'Name', fields: 'name' },
{ title: 'Lastname', fields: 'lastname' },
{
title: 'Money',
fields: 'money',
valueFormat: ({value}) => `$${value.toFixed(2)}`,
},
],
rows: [
{ name: 'Bruno', lastname: 'Salgado', money: 100.73 },
{ name: 'Pri', lastname: 'Lopes', money: 50 },
],
},
});
Result
|Setting|Type|Description|
|-|-|-|
|columns[].valueFormat
|function
|receives the value and return it formatted|
Intrinsic Value Formats
powerful-table
have some native formatations.
The table automatically transforms the value and apply some styles to the column.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{
title: 'Number',
fields: 'number',
valueFormat: 'number'
},
{
title: 'Percentage',
fields: 'percentage',
valueFormat: 'percentage'
},
{
title: 'Currency',
fields: 'currency',
valueFormat: 'currency'
},
{
title: 'Date',
fields: 'date',
valueFormat: 'date'
},
],
rows: [
{
number: 10,
percentage: 23.7,
currency: 100.51,
date: '2017-09-30'
}
]
},
});
Result
|Setting|Type|Description|
|-|-|-|
|columns[].valueFormat
|string
|options: number
, percentage
, currency
or date
|
Custom Intrinsic Value Formats
The intrinsic formats have custom options.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{
title: 'Number',
fields: 'number',
valueFormat: {
format: 'number',
decimals: 0,
},
},
{
title: 'Percentage',
fields: 'percentage',
valueFormat: {
format: 'percentage',
decimals: 0,
symbol: '@', // "@" is just for simulation
}
},
{
title: 'Currency',
fields: 'currency',
valueFormat: {
format: 'currency',
decimals: 0,
symbol: '€',
}
},
{
title: 'Date',
fields: 'date',
valueFormat: {
format: 'date',
input: 'YYYY-MM-DD',
output: 'MMMM, DD of YYYY',
}
},
],
rows: [
{
number: 10,
percentage: 23.7,
currency: 100.51,
date: '2017-09-30'
}
]
},
});
Result
|Setting|Type|Description|
|-|-|-|
|columns[].valueFormat
|object
|formatation settings|
|columns[].valueFormat.format
|string
|options: number
, percentage
, currency
or date
|
Extra options based on format
|Format|Option|Description|
|-|-|-|
|number
|decimals
|decimal places count|
|percentage
|decimals
|decimal places count|
|percentage
|symbol
|char to concat with the value|
|currency
|decimals
|decimal places count|
|currency
|symbol
|char to concat with the value|
|date
|input
|input date format(s) (see: momentjs)|
|date
|ouput
|output date format (see: momentjs)|
Global Instrinsic Value Formats
You can configure valueFormat
settings for all powerful-table
on environment.
// config/environment.js
module.exports = function(environment) {
let ENV = {
...
APP: {
...
table: {
valueFormats: {
number: {
decimals: 1,
},
percentage: {
decimals: 1,
symbol: '',
},
currency: {
decimals: 1,
symbol: 'R$',
},
date: {
input: 'MM/DD/YYYY',
output: 'DD/MM/YYYY',
},
},
},
}
};
...
return ENV;
};
Result
Composed Values
The columns[].valueFormat
also receives all row
data.
You can use to decide the final value or to group values.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{
title: 'Name',
valueFormat: ({row}) => `${Ember.get(row, 'name')} ${Ember.get(row, 'lastname')}`,
},
],
rows: [
{ name: 'Bruno', lastname: 'Salgado' },
{ name: 'Pri', lastname: 'Lopes' },
],
},
});
Result
|Setting|Type|Description|
|-|-|-|
|columns[].valueFormat
|function
|receives all row data and return a value|
Computed Values
To optimize the process columns[].valueFormat
is called only when row
is set.
If you want to observe some data to change your final value use columns[].valueComputed
setting.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{ title: 'Value 1', fields: 'value1' },
{ title: 'Value 2', fields: 'value2' },
{
title: 'Total',
fields: 'total',
valueFormat: ({row}) => Ember.get(row, 'value1') * Ember.get(row, 'value2'),
valueComputed: ['value1', 'value2'],
},
],
rows: [
{ value1: 10, value2: 20 },
],
},
init() {
this._super(...arguments);
setTimeout(() => {
Ember.set(this, 'table.rows.0.value1', 20);
Ember.set(this, 'table.rows.0.value2', 30);
}, 3000);
},
});
First state
Second state (after 3 seconds)
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{
title: 'Value 1',
fields: 'value1',
valueComputed: 'value1',
},
{
title: 'Value 2',
fields: 'value2',
valueComputed: 'value2',
},
{
title: 'Total',
fields: 'total',
valueFormat: ({row}) => Ember.get(row, 'value1') * Ember.get(row, 'value2'),
valueComputed: ['value1', 'value2'],
},
],
rows: [
{ value1: 10, value2: 20 },
],
},
init() {
this._super(...arguments);
setTimeout(() => {
Ember.set(this, 'table.rows.0.value1', 20);
Ember.set(this, 'table.rows.0.value2', 30);
}, 3000);
},
});
First state
Second state (after 3 seconds)
|Setting|Type|Description|
|-|-|-|
|columns[].valueComputed
|string
or array of strings
|observe the data and call valueFormat
on every changing|
Component Values
For a advanced value presentation you can define a component to receive and show the final value.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{
title: 'Product',
fields: 'product',
},
{
title: 'Stars',
fields: 'stars',
component: 'column-stars',
},
],
rows: [
{
product: 'Beer',
stars: 5,
},
{
product: 'Socks',
stars: 1,
},
],
},
});
// components/column-stars.js
export default Ember.Component.extend({
_stars: Ember.computed('value', function(){
let value = Ember.get(this, 'value');
return new Array(value);
}),
});
{{!-- templates/components/column-stars.hbs --}}
{{#each _stars as |star|}}
<span>★</span>
{{/each}}
Result
|Setting|Type|Description|
|-|-|-|
|columns[].component
|string
|path to component; it receives value
(original value), formatedValue
(value returned by valueFormat
), col
(column settings) and row
(row data)|
Sorting
All columns (with fields
attribute filled) are sortable by default.
To disable the sorting on a column use columns[].sorting.enabled
setting.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{
title: 'Name',
fields: 'name',
sorting: { enabled: false },
},
{ title: 'Lastname', fields: 'lastname' },
],
rows: [
{ name: 'Bruno', lastname: 'Salgado' },
{ name: 'Pri', lastname: 'Lopes' },
],
},
});
Result
|Setting|Type|Description|
|-|-|-|
|columns[].sorting
|object
|sorting settings|
|columns[].sorting.enabled
|boolean
|define if the column can be sorted|
Initial Sorting
Show sorted rows on init using sorting
settings.
export default Ember.Controller.extend({
myTableSettings: {
sorting: {
col: 0,
order: 'desc',
},
columns: [
{ title: 'Name', fields: 'name' },
{ title: 'Lastname', fields: 'lastname' },
],
rows: [
{ name: 'Bruno', lastname: 'Salgado' },
{ name: 'Pri', lastname: 'Lopes' },
],
},
});
Result
|Setting|Type|Description|
|-|-|-|
|sorting
|object
|sorting settings|
|sorting.col
|number
|column index|
|sorting.order
|string
|ordination: 'asc'
or 'desc'
|
Trigger Action
Create an action clicking on the cell value.
You can open a modal, do a route transition or whatever you want/need.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{ title: 'Name', fields: 'name' },
{ title: 'Lastname', fields: 'lastname' },
{
fields: 'age',
valueFormat: () => 'get age',
trigger: ({value, row}) => alert(`${Ember.get(row, 'name')} is ${value} years old`)
}
],
rows: [
{ name: 'Bruno', lastname: 'Salgado', age: 32 },
{ name: 'Pri', lastname: 'Lopes', age: 29 },
],
},
});
Result
|Setting|Type|Description|
|-|-|-|
|columns[].trigger
|function
|triggered on cell click; it receives value
(original value), formatedValue
(value returned by valueFormat
), col
(column settings) and row
(row data)|
Show Details
A column can open/close details using columns[].details
settings.powerful-table
send a showDetails
status to columns[].valueFormat
, so you can change the cell value.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{
details: 'row-detail',
valueFormat: ({showDetails}) => showDetails ? Ember.String.htmlSafe('⇩') : Ember.String.htmlSafe('⇨'),
valueComputed: ['showDetails'],
},
{ title: 'Name', fields: 'name' },
{ title: 'Lastname', fields: 'lastname' },
],
rows: [
{ name: 'Bruno', lastname: 'Salgado', description: 'I am a developer' },
{ name: 'Pri', lastname: 'Lopes', description: 'I love my kids' },
],
},
});
{{!-- templates/components/row-detail.hbs --}}
{{row.description}}
Result
|Setting|Type|Description|
|-|-|-|
|columns[].details
|string
|path to the component|
|columns[].valueFormat
|function
|receives showDetails
status|
Details callbacks
Do an action when a detail is opened or closed.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{
details: {
component: 'row-detail',
onOpen: ({row}) => alert(`${Ember.get(row, 'name')} details opened!`),
onClose: ({row}) => alert(`${Ember.get(row, 'name')} details closed!`),
},
valueFormat: ({showDetails}) => showDetails ? htmlSafe('⇩') : htmlSafe('⇨'),
valueComputed: ['showDetails'],
},
{ title: 'Name', fields: 'name' },
{ title: 'Lastname', fields: 'lastname' },
],
rows: [
{ name: 'Bruno', lastname: 'Salgado', description: 'I am a developer' },
{ name: 'Pri', lastname: 'Lopes', description: 'I love my kids' },
],
},
});
Result
|Setting|Type|Description|
|-|-|-|
|columns[].details
|object
|details settings|
|columns[].details.component
|string
|path to the component|
|columns[].details.onOpen
|function
|triggered when details is opened|
|columns[].details.onClose
|function
|triggered when details is closed|
Row Details x Column Details
It's possible to manage the formated value by the showDetails
status of a row, a column or the especific cell.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{ title: 'Name', fields: 'name' },
{ title: 'Lastname', fields: 'lastname' },
{
//watch if this row is showing details (any column)
details: 'row-detail',
valueFormat: ({row}) => row.showDetails ? Ember.String.htmlSafe('⚫') : Ember.String.htmlSafe('⚪'),
valueComputed: ['showDetails'],
},
{
//watch if this especific cell is showing details
details: 'row-detail',
valueFormat: ({showDetails}) => showDetails ? Ember.String.htmlSafe('⚫') : Ember.String.htmlSafe('⚪'),
valueComputed: ['showDetails'],
},
{
//watch if this column is showing details (any row)
details: 'row-detail',
valueFormat: ({col}) => col.showDetails ? Ember.String.htmlSafe('⚫') : Ember.String.htmlSafe('⚪'),
valueComputed: ['showDetails'],
}
],
rows: [
{ name: 'Bruno', lastname: 'Salgado', description: 'I am a developer' },
{ name: 'Pri', lastname: 'Lopes', description: 'I love my kids' },
],
},
});
Result
Clicking on first detail column
Clicking on second detail column
Clicking on third detail column
|Parameter|Type|Description|
|-|-|-|
|row.showDetails
|boolean
|indicate if some column is showing details in this row|
|col.showDetails
|boolean
|indicate if some detail is open on this column, independent of the row|
|showDetails
|boolean
|indicate if the especific cell is showing details|
Details table
Show a powerful-table
as a detail.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{
details: 'orders-detail',
valueFormat: ({showDetails}) => showDetails ? Ember.String.htmlSafe('⇩') : Ember.String.htmlSafe('⇨'),
valueComputed: ['showDetails'],
},
{ title: 'Name', fields: 'name' },
{ title: 'Lastname', fields: 'lastname' },
],
rows: [
{
name: 'Bruno',
lastname: 'Salgado',
orders: [
{
id: 1,
total: 1730,
items: [
{ id: 1, description: 'Notebook', price: 1000 },
{ id: 2, description: 'Beer', price: 730 },
],
},
],
},
{
name: 'Pri',
lastname: 'Lopes',
orders: [
{
id: 2,
total: 324.57,
items: [
{ id: 3, description: 'Shoes', price: 300 },
{ id: 4, description: 'Wine', price: 24.57 },
],
},
],
},
],
},
});
// components/orders-detail.js
export default Ember.Component.extend({
tableOrdersSettings: Ember.computed(function(){
return {
columns: [
{
details: 'order-items-detail',
valueFormat: ({showDetails}) => showDetails ? Ember.String.htmlSafe('⇩') : Ember.String.htmlSafe('⇨'),
valueComputed: ['showDetails'],
},
{ title: 'ID', fields: 'id' },
{
title: 'Total',
fields: 'total',
valueFormat: ({value}) => `$${value.toFixed(2)}`,
},
],
rows: Ember.get(this, 'row.orders'),
};
}),
});
{{!-- templates/components/orders-detail.hbs --}}
<strong>Orders:</strong>
{{powerful-table table=tableOrdersSettings}}
// components/order-items-detail.js
export default Ember.Component.extend({
tableItemsSettings: Ember.computed(function(){
return {
columns: [
{ title: 'ID', fields: 'id' },
{ title: 'Item', fields: 'description' },
{
title: 'Price',
fields: 'price',
valueFormat: ({value}) => `$${value.toFixed(2)}`,
},
],
rows: Ember.get(this, 'row.items'),
};
}),
});
{{!-- templates/components/order-items-detail.hbs --}}
<strong>Items:</strong>
{{powerful-table table=tableItemsSettings}}
First state
Person details
Order details
No Results
Settings to handle when the table has no data.
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{ title: 'Name', fields: 'name' },
{ title: 'Lastname', fields: 'lastname' },
],
rows: [],
noResults: {
message: 'No data found',
},
},
});
Result
|Setting|Type|Description|
|-|-|-|
|noResults
|object
|settings for a empty table|
|noResults.message
|string
|text to warn about empty data|
Global No Results
Configure noResults
settings for all powerful-table
on environment.
// config/environment.js
module.exports = function(environment) {
let ENV = {
...
APP: {
...
table: {
noResults: {
message: 'No data found',
},
},
}
};
...
return ENV;
};
Styling
Make it pretty!
export default Ember.Controller.extend({
myTableSettings: {
columns: [
{
title: 'Date',
fields: 'date',
valueFormat: 'date',
headClass: 'date',
bodyClass: 'date',
},
{
title: 'Description',
fields: 'description',
headClass: 'description',
bodyClass: 'description',
},
{
title: 'Value',
fields: 'value',
valueFormat: 'currency',
headClass: 'value',
bodyClass: {
'value-positive:value-negative': ({value}) => value >= 0,
},
},
],
rows: [
{
date: '2017-09-01',
description: 'Salary',
value: 990,
},
{
date: '2017-09-05',
description: 'Restaurant',
value: -100.5,
},
{
date: '2017-09-07',
description: 'Gasoline',
value: -37,
},
],
},
});
/* app/styles/app.css */
.ember-powerful-table {
border: 1px solid #ccc;
font-family: Tahoma;
font-size: 12px;
}
.ember-powerful-table thead {
background-color: #ccc;
}
.ember-powerful-table tr:nth-child(even) {
background-color: #f2f2f2;
}
.ember-powerful-table th.date:before {
content: '#';
display: inline-block;
}
.ember-powerful-table td.date {
font-weight: bold;
}
.ember-powerful-table .description {
text-align: center;
}
.ember-powerful-table th.value {
text-align: right;
}
.ember-powerful-table td.value-positive {
color: blue;
}
.ember-powerful-table td.value-negative {
color: red;
}
Result
|Setting|Type|Description|
|-|-|-|
|headClass
|string
|header css classes|
|bodyClass
|string
|body css classes|
|bodyClass
|object
|the attribute name is the css classes and the value is a function which determine if it's to apply; separate the classes names by ':' to apply true or false classes, respectively; it receives value
(original value), formatedValue
(value returned by valueFormat
), col
(column settings) and row
(row data)|