diff --git a/.gitignore b/.gitignore
index 5ad14dd..576aad4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,4 @@
/libpeerconnection.log
npm-debug.log*
testem.log
+/docs/*
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 704b832..668cc30 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,17 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
+## [0.2.0] - 2017-05-17 - Ember v2.X.X
+### Added
+- Adds ability to set column filter/sort independently.
+- Add support for YUIDocs for better API documentation.
+
+### Changed
+- Upgrades ember-power-select to 1.4.3, may require refactoring of `class` to `triggerClass` if applicable.
+- Upgrade ember and ember-cli to 2.10.0
+
+### Fixed
+
## [0.1.0] - 2016-08-31 - Ember pre v1.13.10
### Added
- Initial base version built to support JSON API v1.0.
@@ -14,14 +25,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Add subcomponent to change the table limit/count.
- Setup `autoHide` computed property to conditionally hide the limit dropdown if the results are smaller than the smallest pagination limit.
- Adds ability to persist data across transitions, setting `persistFiltering: true` and sharing the `filter`/`sort` properties with a controller/service.
-- Adds ability to set column filter/sort independently.
### Changed
- Update legacy name references in README.md.
- Removed ember-canary from ember-try testing scenarios.
- Removed ember-beta from ember-try testing scenarios.
-- Upgrades ember-power-select to 1.4.3, may require refactoring of `class` to `triggerClass` if applicable.
-- Upgrade ember and ember-cli to 2.10.0
### Fixed
- Fix erring ember try in ember-canary, properly remove component element wrapper.
diff --git a/README.md b/README.md
index e79089f..76d6873 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,7 @@ You have full control over your table's `tbody` content. We are setting this to
{{row.emailAddress}}
{{row.firstName}}
{{row.lastName}}
+
{{row.updatedAt}}
{{#link-to "index" class="btn btn-xs" role="button"}}
Edit
@@ -75,10 +76,15 @@ export default Ember.Controller.extend({
label: 'Last Updated',
type: 'date',
},
+ {
+ label: 'Actions',
+ },
],
});
```
+* Reference the [API specs/documentation](/docs/index.html) for more information and for advanced usage.
+
### Request Format
Ember Tabular sticks very closely to jsonapi spec, a few examples of requests:
@@ -90,93 +96,6 @@ Ember Tabular sticks very closely to jsonapi spec, a few examples of requests:
* `sort` - Sort based on jsonapi's recommended sorting: http://jsonapi.org/format/#fetching-sorting
* Ascending unless prefixed with `-` for descending.
-## Advanced Usage
-### Template
-```hbs
-{{#ember-tabular
- columns=columns
- modelName="user"
- record=users
- class="table-default"
- tableClass="table-bordered table-hover table-striped"
- staticParams=staticParams
- as |section|}}
- ...
-{{/ember-tabular}}
-```
-* `makeRequest` - boolean/string - Default: true
- * If `true`: Ember Tabular will make request based on `modelName`.
- * If `false`: Typically you'd bind the route's model to `record`.
-* `class` - string
- * Wraps the entire component.
-* `tableClass` - string - Default: "table-bordered table-hover"
- * Wraps only the `
` and replaces defaults if provided.
-* `staticParams` - object - Default: null
- * Object to pass in static query-params that will not change based on any filter/sort criteria, ex. additional table-wide filters that need to be applied in all requests `?filter[is-open]=1`.
-
- ```js
- // app/controllers/location.js
-
- export default Ember.Controller.extend({
- staticParams: Ember.computed('model', function() {
- return {
- 'filter[is-open]': '1',
- 'include': 'hours',
- };
- }),
- ...
- });
- ```
-* `tableLoadedMessage` - string - Default: "No Data."
- * In some cases when the API response is loaded but does not contain any data "No Data." will not apply, on a case by case basis you can override this. For example, if you'd like to prompt the user to do some kind of action. "No data, select a different product".
-
-### Controller
-```js
-export default Ember.Controller.extend({
- users: null,
- columns: [
- {
- property: 'username',
- label: 'Username',
- defaultSort: 'username',
- type: 'text',
- },
- {
- property: 'emailAddress',
- label: 'Email',
- type: 'text',
- },
- {
- property: 'firstName',
- label: 'First Name',
- type: 'text',
- },
- {
- property: 'lastName',
- label: 'Last Name',
- type: 'text',
- },
- {
- property: 'updatedAt',
- label: 'Last Updated',
- type: 'date',
- },
- ],
-});
-```
-* `columns.property` - string
- * Required for column filtering/sorting
- * Properties should be in camelCase format
-* `columns.label` - string
- * Required in all use-cases
-* `columns.type` - string - Default: text
- * Sets the filter ``
-* `columns.sort` - boolean - Default: true
- * Required for column sorting
-* `columns.defaultSort` - string
- * Initial sort value for API request
- * Will be overridden with any sorting changes
-
### Template - Yields
```hbs
{{#ember-tabular columns=columns record=users as |section|}}
@@ -206,26 +125,6 @@ Typically the global filter component would be rendered into the `{{yield header
filterProperty="username"
filterPlaceholder="Search by Username"}}
```
-* `filter` - object - Default: null
- * Required
- * Must also expose the `filter` property on the parent `ember-tabular` component to be able to pass the `filter` object back and forth between parent and child components.
-* `query` - object - Default: `this.get('query') || this.get('parentView.query')`
- * Pass the query object from the parent component if it is different or if used outside of the context of the component, otherwise query is optional and it component will attempt to grab within the context of the parent component.
-* `filterProperty` - string - Default: null
- * Required
- * Used with the "Global Filter Sub-Component".
- * Pass the property name in camelCase format.
-* `filterPlaceholder` - string - Default: null
- * Optional
- * Placeholder to be used for the global-filter.
-* `label` - string - Default: null
- * Optional
- * Set a label on the global-filter.
-* `inputClass` - string - Default: null
- * Optional
- * Wraps the input field in a div.
-* `labelClass` - string - Default: null
- * Optional
#### Date Filter
Date filter changes `input type="date"` to take advantage of a browser's HTML5 date widget. Typically the date filter component would be rendered into the `{{yield header}}` of the main table component using the yield conditional `{{#if section.isHeader}} ...`. However, it can be used outside of the context of the main component if the proper properties are shared between the main component and sub-component.
@@ -237,26 +136,51 @@ Date filter changes `input type="date"` to take advantage of a browser's HTML5 d
filterProperty="updatedAt"
label="Last Updated"}}
```
-* `filter` - object - Default: null
- * Required
- * Must also expose the `filter` property on the parent `ember-tabular` component to be able to pass the `filter` object back and forth between parent and child components.
-* `query` - object - Default: `this.get('query') || this.get('parentView.query')`
- * Pass the query object from the parent component if it is different or if used outside of the context of the component, otherwise query is optional and it component will attempt to grab within the context of the parent component.
-* `filterProperty` - string - Default: null
- * Required
- * Used with the "Global Filter Sub-Component".
- * Pass the property name in camelCase format.
-* `dateFilter` - string - Default: null
- * Optional
- * Sets the input value.
-* `label` - string - Default: null
- * Optional
- * Set a label on the global-filter.
-* `inputClass` - string - Default: null
- * Optional
- * Wraps the input field in a div.
-* `labelClass` - string - Default: null
- * Optional
+
+#### Dropdown Filter
+Use the dropdown filter globally. One way to do this is by setting up a computed property that returns an array of label/value objects.
+
+```js
+
+export default Ember.Controller.extend({
+ users: null,
+ actions: {
+ setIsAdminFilter(object) {
+ if (object) {
+ this.set('isAdminFilter', object.value);
+ } else {
+ this.set('isAdminFilter', null);
+ }
+ },
+ },
+ adminContent: Ember.computed(function() {
+ return [
+ {
+ label: 'Yes',
+ value: true,
+ },
+ {
+ label: 'No',
+ value: false,
+ },
+ ];
+ }),
+});
+```
+```hbs
+{{#ember-tabular-dropdown-filter filter=filter filterProperty="isAdmin" label="Is Admin" searchFilter=isAdminFilter}}
+ {{#power-select
+ options=adminContent
+ selected=(find-by adminContent 'value' isAdminFilter)
+ searchField="label"
+ searchEnabled=false
+ placeholder="Select to filter"
+ onchange=(action "setIsAdminFilter")
+ as |option|}}
+ {{option.label}}
+ {{/power-select}}
+{{/ember-tabular-dropdown-filter}}
+```
## Note
* This component adheres to jsonapi spec: http://jsonapi.org/
@@ -274,44 +198,7 @@ If you are using Ember Data, then you can lean on your application's custom adap
* Filtering
* This addon expects a `filter` object with nested property/value pairs.
-If you are not using Ember Data then you can extend this addon's component and override a set of serialize and normalized methods:
-```js
-import EmberTabular from 'ember-tabular/components/ember-tabular';
-
-export default EmberTabular.extend({
- serializePagination(params) {
- // override default pagination ?page[offset]= and ?[page]limit=
- // offset and limit will be sent as ?offset= and ?limit=
- params.offset = (params.page * params.limit) - params.limit;
- if (isNaN(params.offset)) {
- params.offset = null;
- }
-
- return params;
- },
-});
-```
-```js
-import EmberTabular from 'ember-tabular/components/ember-tabular';
-
-export default EmberTabular.extend({
- serializeProperty(property) {
- // Override to convert all properties sent in requests to camelize instead of the default dasherized
- // ?filter[lastName]&sort=isAdmin
- // (pseudo code)
- if (property) {
- return Ember.String.camelize(property);
- }
-
- return null;
- },
-});
-```
-Check add-on source for full list of serialized/normalized methods available for extension.
-Note:
-
-* On success you must set the `record` with the array of table data
-
+If you are not using Ember Data or following json:api then you can extend this component and override a set of serialize and normalized methods, checkout the [API specs/documentation](/docs/index.html) for more details/examples.
# Contributing to this addon
## Installation
diff --git a/addon/components/ember-tabular-alert.js b/addon/components/ember-tabular-alert.js
index 25b3be3..9f70d56 100644
--- a/addon/components/ember-tabular-alert.js
+++ b/addon/components/ember-tabular-alert.js
@@ -1,8 +1,28 @@
import Ember from 'ember';
+/**
+* Any errors returned from the request(s) are displayed in an alert box.
+*
+* @class EmberTabularAlert
+*/
export default Ember.Component.extend({
+ /**
+ * @property tagName
+ * @type String
+ * @default 'div'
+ */
tagName: 'div',
+ /**
+ * @property type
+ * @type String
+ * @default 'info'
+ */
type: 'info',
+ /**
+ * @property typeClass
+ * @type String
+ * @default 'alert-[type]'
+ */
typeClass: Ember.computed('type', function () {
return `alert-${this.get('type')}`;
}),
diff --git a/addon/components/ember-tabular-date-filter.js b/addon/components/ember-tabular-date-filter.js
index 82aded6..49a57eb 100644
--- a/addon/components/ember-tabular-date-filter.js
+++ b/addon/components/ember-tabular-date-filter.js
@@ -1,3 +1,18 @@
import EmberTabularGlobalFilter from './ember-tabular-global-filter';
+/**
+* ## Date Filter
+* Date filter changes `input type="date"` to take advantage of a browser's HTML5 date widget. Typically the date filter component would be rendered into the `{{yield header}}` of the main table component using the yield conditional `{{#if section.isHeader}} ...`.
+*
+* However, it can be used outside of the context of the main component if the proper properties are shared between the main component and sub-component.
+*
+* - Sent in request as: `?filter[filterProperty]=dateFilter`, e.g. `?filter[updated-at]=2015-06-29`
+```hbs
+{{ember-tabular-date-filter
+ filter=filter
+ filterProperty="updatedAt"
+ label="Last Updated"}}
+```
+* @class EmberTabularDateFilter
+*/
export default EmberTabularGlobalFilter.extend();
diff --git a/addon/components/ember-tabular-dropdown-filter.js b/addon/components/ember-tabular-dropdown-filter.js
index 82aded6..de7bf7a 100644
--- a/addon/components/ember-tabular-dropdown-filter.js
+++ b/addon/components/ember-tabular-dropdown-filter.js
@@ -1,3 +1,50 @@
import EmberTabularGlobalFilter from './ember-tabular-global-filter';
+/**
+* ## Dropdown Filter
+* Use the dropdown filter globally. One way to do this is by setting up a computed property that returns an array of label/value objects.
+```js
+export default Ember.Controller.extend({
+ users: null,
+ actions: {
+ setIsAdminFilter(object) {
+ if (object) {
+ this.set('isAdminFilter', object.value);
+ } else {
+ this.set('isAdminFilter', null);
+ }
+ },
+ },
+ adminContent: Ember.computed(function() {
+ return [
+ {
+ label: 'Yes',
+ value: true,
+ },
+ {
+ label: 'No',
+ value: false,
+ }
+ ];
+ }),
+});
+```
+```hbs
+{{#ember-tabular-dropdown-filter filter=filter filterProperty="isAdmin" label="Is Admin" searchFilter=isAdminFilter}}
+ {{#power-select
+ options=adminContent
+ selected=(find-by adminContent 'value' isAdminFilter)
+ searchField="label"
+ searchEnabled=false
+ placeholder="Select to filter"
+ onchange=(action "setIsAdminFilter")
+ as |option|}}
+ {{option.label}}
+ {{/power-select}}
+{{/ember-tabular-dropdown-filter}}
+```
+*
+* @class EmberTabularDropdownFilter
+* @extends EmberTabularGlobalFilter
+*/
export default EmberTabularGlobalFilter.extend();
diff --git a/addon/components/ember-tabular-dropdown-limit.js b/addon/components/ember-tabular-dropdown-limit.js
index e69f03a..77b4df3 100644
--- a/addon/components/ember-tabular-dropdown-limit.js
+++ b/addon/components/ember-tabular-dropdown-limit.js
@@ -1,12 +1,34 @@
import Ember from 'ember';
+/**
+* Sets up component for changing the table row count/limit.
+*
+* @class EmberTabularDropdownLimit
+*/
export default Ember.Component.extend({
+ /**
+ * @property tagName
+ * @type String
+ * @default 'div'
+ */
tagName: 'div',
classNames: ['ember-tabular-dropdown-limit'],
- // populates limit dropdown
+ /**
+ * @property limits
+ * @type Array
+ * @default [10, 25, 50, 100, 500]
+ */
limits: [10, 25, 50, 100, 500],
+ /**
+ * Computed Property to determine if the result set is large enough to display the dropdown limit component.
+ *
+ * @property autoHide
+ * @param record
+ * @param count
+ * @return Boolean
+ */
autoHide: Ember.computed('record', 'count', function() {
let record = this.get('record');
let count = this.get('count');
diff --git a/addon/components/ember-tabular-filter.js b/addon/components/ember-tabular-filter.js
index 718273a..e27c11a 100644
--- a/addon/components/ember-tabular-filter.js
+++ b/addon/components/ember-tabular-filter.js
@@ -1,11 +1,42 @@
import Ember from 'ember';
+/**
+* Filtering on a column by column basis within the component's `
`.
+*
+* @class EmberTabularFilter
+*/
export default Ember.Component.extend({
+ /**
+ * @property tagName
+ * @type String
+ * @default 'th'
+ */
tagName: 'th',
action: null,
+ /**
+ * Value of filter.
+ *
+ * @property headerFilter
+ * @type String
+ * @default ''
+ */
headerFilter: '',
+ /**
+ * Pass the `query` object from the parent component if it is different or if used outside of the context of the component, otherwise `query` is optional and the component will attempt to grab within the context of the parent component.
+ *
+ * @property query
+ * @type Object
+ * @default null
+ */
query: null,
+ /**
+ * Must expose the `filter` property on the parent ember-tabular component to be able to pass the filter object back and forth between parent and child components.
+ *
+ * @property filter
+ * @type Object
+ * @default null
+ */
filter: null,
actions: {
@@ -35,10 +66,18 @@ export default Ember.Component.extend({
// to avoid multiple requests for properties that are set on init
this.addObserver('headerFilter', this.filterBy);
}),
- // observable property is set during init
- filterBy: Ember.observer(function () {
+ /**
+ * Debounce the `filterName` method.
+ * observable property is set during init
+ *
+ * @method filterBy
+ */
+ filterBy() {
Ember.run.debounce(this, 'filterName', 750);
- }),
+ },
+ /**
+ * @property isClearable
+ */
isClearable: Ember.computed('headerFilter', function () {
if (this.get('headerFilter')) {
return true;
@@ -52,6 +91,11 @@ export default Ember.Component.extend({
return 'YYYY-MM-DD';
}
}),
+ /**
+ * Constructs and sets the `filter` Object.
+ *
+ * @method filterName
+ */
filterName() {
const query = this.get('query');
const property = this.get('property');
diff --git a/addon/components/ember-tabular-global-filter.js b/addon/components/ember-tabular-global-filter.js
index bcc5371..975805e 100644
--- a/addon/components/ember-tabular-global-filter.js
+++ b/addon/components/ember-tabular-global-filter.js
@@ -1,12 +1,54 @@
import Ember from 'ember';
+/**
+* ## Global Filter
+* Typically the global filter component would be rendered into the `{{yield header}}` of the main table component using the yield conditional `{{#if section.isHeader}} ...`.
+*
+* However, it can be used outside of the context of the main component if the proper properties are shared between the main component and sub-component.
+
+* - Sent in request as: `?filter[filterProperty]=searchFilter`, e.g. `?filter[username]=John.Doe2`
+```hbs
+{{ember-tabular-global-filter
+ filter=filter
+ filterProperty="username"
+ filterPlaceholder="Search by Username"}}
+```
+*
+* @class EmberTabularGlobalFilter
+*/
export default Ember.Component.extend({
+ /**
+ * @property tagName
+ * @type String
+ * @default 'div'
+ */
tagName: 'div',
classNames: ['table-filter'],
action: null,
+ /**
+ * Property to be filtered upon.
+ *
+ * @property filterProperty
+ * @type String
+ * @default null
+ */
filterProperty: null,
+ /**
+ * Value of filter.
+ *
+ * @property searchFilter
+ * @type String
+ * @default ''
+ */
searchFilter: '',
+ /**
+ * Pass the `query` object from the parent component if it is different or if used outside of the context of the component, otherwise `query` is optional and the component will attempt to grab within the context of the parent component.
+ *
+ * @property query
+ * @type Object
+ * @default null
+ */
query: null,
filter: null,
@@ -15,15 +57,29 @@ export default Ember.Component.extend({
this.set('searchFilter', '');
},
},
+ /**
+ * Debounce the `filterName` method.
+ *
+ * @method filterTable
+ */
filterTable: Ember.observer('searchFilter', function () {
Ember.run.debounce(this, 'filterName', 750);
}),
+ /**
+ * @property isClearable
+ * @default false
+ */
isClearable: Ember.computed('searchFilter', function () {
if (this.get('searchFilter')) {
return true;
}
return false;
}),
+ /**
+ * Constructs and sets the `filter` Object.
+ *
+ * @method filterName
+ */
filterName() {
// Reference parent component query obj
const query = this.get('query') || this.get('parentView.query');
diff --git a/addon/components/ember-tabular.js b/addon/components/ember-tabular.js
index 0e46c05..26774f8 100644
--- a/addon/components/ember-tabular.js
+++ b/addon/components/ember-tabular.js
@@ -1,15 +1,135 @@
import Ember from 'ember';
+/**
+* ## Basic Usage
+* - `columns` - Controller array to setup the table headers/columns (detailed below).
+ - `modelName` - for the component to make the proper request when filtering/sorting, you must pass the model type matching your Ember model structure. e.g. brand/diagram, product.
+ - `record` - this is bound to the controller and is used to iterate over the table's model data.
+* ### Template
+ ```hbs
+ {{! app/templates/my-route.hbs }}
+
+ {{#ember-tabular columns=columns modelName="user" record=users as |section|}}
+ {{#if section.isBody}}
+ {{#each users as |row|}}
+