addsearch-search-ui
Version:
JavaScript library to develop Search UIs for the web
177 lines (153 loc) • 5.27 kB
JavaScript
import './activefilters.scss';
import handlebars from 'handlebars';
import { ACTIVE_FILTERS_TEMPLATE } from './templates';
import {
toggleFacetFilter,
toggleFilter,
setRangeFilter,
clearSelected,
toggleHierarchicalFacetFilter, toggleRangeFacetFilter
} from '../../actions/filters';
import { validateContainer } from '../../util/dom';
import { observeStoreByKey } from '../../store';
const TYPE = {
FILTER: 'FILTER',
RANGE_FILTER: 'RANGE_FILTER',
FACET: 'FACET',
RANGE_FACET: 'RANGE_FACET',
HIERARCHICAL_FACET: 'HIERARCHICAL_FACET'
}
export default class ActiveFilters {
constructor(client, reduxStore, conf) {
this.client = client;
this.conf = conf;
this.reduxStore = reduxStore;
if (validateContainer(conf.containerId)) {
observeStoreByKey(this.reduxStore, 'filters', (state) => this.render(state));
}
}
getFilterLabel(filterName, allAvailableFilters) {
for (let i=0; i<allAvailableFilters.length; i++) {
if (allAvailableFilters[i][filterName]) {
return allAvailableFilters[i][filterName].label;
}
}
}
emptyIfNull(val) {
if (val === null || val === undefined) {
return '';
}
return val;
}
render(filterState) {
let active = [];
// Filters
for (let key in filterState.activeFilters) {
active.push({
type: TYPE.FILTER,
name: key,
value: filterState.activeFilters[key],
label: this.getFilterLabel(key, filterState.allAvailableFilters)
});
}
// Range filters
for (let key in filterState.activeRangeFilters) {
const rangeVal = filterState.activeRangeFilters[key];
active.push({
type: TYPE.RANGE_FILTER,
name: key,
label: this.getFilterLabel(key, filterState.allAvailableFilters) + ': ' + this.emptyIfNull(rangeVal.gte) + '-' + this.emptyIfNull(rangeVal.lte)
});
}
// Facets
for (let key in filterState.activeFacets) {
// Category and custom field facets
if (key === 'category' || key.indexOf('custom_fields.') === 0) {
for (var category in filterState.activeFacets[key]) {
active.push({
name: key,
type: TYPE.FACET,
value: category,
label: category.replace(/^[0-9]+[x]{1}/, '')
});
}
}
}
// Hierarchical facets
for (let container in filterState.activeHierarchicalFacets) {
for (let field in filterState.activeHierarchicalFacets[container]) {
for (let facetValue in filterState.activeHierarchicalFacets[container][field]) {
active.push({
name: field,
type: TYPE.HIERARCHICAL_FACET,
container: container,
value: facetValue,
label: facetValue
});
}
}
}
// Range facets
for (let field in filterState.activeRangeFacets) {
for (let key in filterState.activeRangeFacets[field]) {
active.push({
name: field,
type: TYPE.RANGE_FACET,
value: key,
label: key,
rangeMin: filterState.activeRangeFacets[field][key].gte,
rangeMax: filterState.activeRangeFacets[field][key].lt
});
}
}
const data = {
active,
clearAll: this.conf.clearAll !== false
};
// Compile HTML and inject to element if changed
const html = handlebars.compile(this.conf.template || ACTIVE_FILTERS_TEMPLATE)(data);
if (this.renderedHtml === html) {
return;
}
const container = document.getElementById(this.conf.containerId);
container.innerHTML = html;
this.renderedHtml = html;
// Attach events
const elems = container.querySelectorAll('[data-type]');
for (let i = 0; i < elems.length; i++) {
elems[i].addEventListener('click', (e) => this.handleFilterClick(e));
}
const clearAll = container.querySelector('[data-clearall]');
if (clearAll) {
clearAll.addEventListener('click', (e) => this.reduxStore.dispatch(clearSelected(true, true)));
}
}
handleFilterClick(e) {
const type = e.target.getAttribute('data-type');
const name = e.target.getAttribute('data-name');
const value = e.target.getAttribute('data-value');
const container = e.target.getAttribute('data-container');
const confFields = e.target.getAttribute('data-conf-fields') ? e.target.getAttribute('data-conf-fields').split(',') : [];
const rangeMin = e.target.getAttribute('data-range-min');
const rangeMax = e.target.getAttribute('data-range-max');
if (type === TYPE.FILTER) {
this.reduxStore.dispatch(toggleFilter(name, value, true));
}
else if (type === TYPE.RANGE_FILTER) {
this.reduxStore.dispatch(setRangeFilter(name, null, null));
}
else if (type === TYPE.FACET) {
this.reduxStore.dispatch(toggleFacetFilter(name, value));
}
else if (type === TYPE.HIERARCHICAL_FACET) {
this.reduxStore.dispatch(toggleHierarchicalFacetFilter(name, container, confFields, value, true))
}
else if (type === TYPE.RANGE_FACET) {
const values = {
min: rangeMin,
max: rangeMax
};
this.reduxStore.dispatch(toggleRangeFacetFilter(name, values, value, true, true))
}
}
}