feat: 🎸 initial resource filter param system

This commit is contained in:
Randall Morey committed 2021-11-09 20:09:23 -05:00
1 parent ac1d54565c
commit 84511ba6d4
3 files changed
+157

No files matched your search

@@ -0,0 +1,83 @@
/**
* A resource filter param is a concise way to express a route query parameter.
* Resource filter params abstract away a route's query parameter
* interface, treating a query param as a simple attribute on a route instance.
* Getting the attribute value is equivalent to looking up the associated query
* parameter. Setting the attribute is equivalent to transitioning to the route
* and passing the associated query parameter value.
*
* Additionally, resource filter params may declare `allowedValues`, an array
* containing the set of values the parameter may take. While unenforced,
* `allowedValues` are useful metadata about a resource filter and may be fetch
* via `ResourceFilterParamHelper`.
*
* @see ResourceFilterParamHelper
*
* @example
*
* export default class ScopesScopeAuthMethodsRoute extends Route {
*
* @resourceFilterParam(['active', 'pending'])
* status;
*
* @action
* changeStatus(status) {
* // Sets query param `filter-status` on the current route, which occurs
* // via a route transition.
* this.status = status;
* // Log the value of query param `filter-status`.
* console.log(this.status);
* }
* }
*
*/
export function resourceFilterParam(allowedValues) {
/**
* @param {object} target
* @param {string} name
* @param {object} descriptor
* @return {object{get, set}}
*/
return function (target, name /*, descriptor*/) {
const filterName = `filter-${name}`;
const filterOptionsName = `filter-options-${name}`;
// If the route has no query params specified yet, declare them.
if (!Object.keys(target.queryParams).length) target.queryParams = {};
// Add the resource filter query parameter to the route. Resource filter
// param changes refresh the model but do not contribute to browser history.
// See https://guides.emberjs.com/release/routing/query-params/
target.queryParams[filterName] = {
refreshModel: true,
replace: true,
};
// Store the allowed values for future lookup
// (via `ResourceFilterParamHelper`).
target[filterOptionsName] = allowedValues;
// Override the decorated attribute with a getter and setter.
return {
/**
* Returns the JSON-parsed query parameter value.
*/
get() {
const value = this.currentRoute.queryParams[filterName];
return value ? JSON.parse(value) : null;
},
/**
* Sets the resource filter param to the stringified representation
* of `value`. NOTE: this is equivalent to transitioning into the
* current route, changing the associated query param.
* @param value
*/
set(value) {
const queryParams = {};
queryParams[filterName] = JSON.stringify(value);
this.transitionTo({ queryParams });
},
};
};
}
@@ -0,0 +1,73 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import { getOwner } from '@ember/application';
import { action } from '@ember/object';
/**
* Use this helper to fetch the current value of a resource filter param,
* as well as its allowedValues.
*
* @see resourceFilterParam (decorator)
*
* @example
*
* {{#with resource-filter-param 'status' as |param|}}
* {{param.name}} / {{param.value}} / {{param.selectedValue}}
* {{/with}}
*/
export default class ResourceFilterParamHelper extends Helper {
// =services
@service router;
// =methods
// =lifecycle management methods
/**
* Recompute this helper when the route changes.
*/
constructor() {
super(...arguments);
this.router.on('routeWillChange', this.routeWillChange);
}
/**
* Stop listening to route events when this helper is destroyed.
*/
willDestroy() {
this.router.off('routeWillChange', this.routeWillChange);
super.willDestroy();
}
// =compute method
/**
* Returns an object containing `name`, `value`, and `selectedValue`.
* `name` - The name of the resource filter param.
* `value` - The value of the resource filter param
* @return {object}
*/
compute([routeName, name]) {
const owner = getOwner(this);
// Filter options
const route = owner.lookup(`route:${routeName}`);
const filterOptionsName = `filter-options-${name}`;
const value = route[filterOptionsName];
// Selected filters
const rawValue = route[name];
const selectedValue = rawValue ? JSON.parse(rawValue) : null;
return { name, value, selectedValue };
}
// =actions
/**
* Triggers a recompute (see above) when the route changes, especially when
* route query params change.
*/
@action
routeWillChange() {
this.recompute();
}
}
@@ -0,0 +1 @@
export { default } from 'core/helpers/resource-filter-param';