diff --git a/.gitignore b/.gitignore
index 86fceae..2591bb1 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 4058b92..c04cccc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Add additional configurable wrapper classes for additional styling.
- 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.
+- Add support for YuiDocs for better API documentation.
+- Setup deployment to gh-pages for demo URL.
### Changed
- Update legacy name references in README.md.
diff --git a/README.md b/README.md
index e79089f..b50ea26 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,92 +96,7 @@ 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
+## Misc
### Template - Yields
```hbs
@@ -206,26 +127,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 +138,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 +200,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-filter.js b/addon/components/ember-tabular-filter.js
index 666f010..f380290 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: {
@@ -20,15 +51,26 @@ export default Ember.Component.extend({
}
},
},
+ /**
+ * Debounce the `filterName` method.
+ *
+ * @method filterBy
+ */
filterBy: Ember.observer('headerFilter', function () {
Ember.run.debounce(this, 'filterName', 750);
}),
+ /**
+ * @property isClearable
+ */
isClearable: Ember.computed('headerFilter', function () {
if (this.get('headerFilter')) {
return true;
}
return false;
}),
+ /**
+ * @property inputPlaceholder
+ */
inputPlaceholder: Ember.computed('header.type', function () {
const type = this.get('header.type');
@@ -36,6 +78,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..b828ca4 100644
--- a/addon/components/ember-tabular-global-filter.js
+++ b/addon/components/ember-tabular-global-filter.js
@@ -1,13 +1,62 @@
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,
+ /**
+ * 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: {
@@ -15,15 +64,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 32a6385..abac666 100644
--- a/addon/components/ember-tabular.js
+++ b/addon/components/ember-tabular.js
@@ -1,13 +1,127 @@
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|}}
+