UNPKG

react-table-filter-2

Version:
315 lines (279 loc) 9.17 kB
import React from 'react'; import FilterListItem from './filterListItem'; import SelectAllItem from './selectAllItem'; import SearchBar from './searchBar'; import EventStack from './lib/eventStack'; import FilterIcon from './filterIcon'; import SortIcon from './sortIcon'; import PropTypes from 'prop-types'; import { ASC_VALUE, DSC_VALUE, } from './lib/constants'; import { isUndefined, } from './lib/util'; /** * FilterList List of options displayed in the header of the table * @extends React */ class FilterList extends React.Component { /** * constructor * @param {Object} props */ constructor(props) { super(props); this.appliedSearchFilters = undefined; this.searchValue = undefined; this.state = { showFilter: false, searchEnabled: false, lastChecked: -1 }; } /** * componentWillUnmount */ componentWillUnmount() { /* Remove body click listener*/ EventStack.unsub('click', this._handleOutsideClick); } /** * _handleOutsideClick Function to hide open filter list when click is done anywhere else * @param {Event} e */ _handleOutsideClick = (e) => { if (!this.filterIconNode.contains(e.target)) { this._hideFilter(); } } /** * _filterIconClicked function handles click on filter icon * @param {Event} e */ _filterIconClicked = (e) => { const filterState = this.state.showFilter; const newState = !filterState; if (newState) { this._displayFilter(); } else { this._hideFilter(); } } /** * _displayFilter function handles display of filter list */ _displayFilter = () => { /* Body Click listener added*/ EventStack.sub('click', this._handleOutsideClick); this.setState({ showFilter: true, }); } /** * _hideFilter function hides filter list */ _hideFilter = () => { /* Body Click listener removed*/ EventStack.unsub('click', this._handleOutsideClick); this.setState({ showFilter: false, searchEnabled: false, }); } getLessNumber = (one, two) => { if (one < two) { return { less: one, greater: two - 1 } } if (two < one) { return { less: two + 1, greater: one } } return { less: one, greater: two } } _handleSelectionRange = (index, event) => { if (event.shiftKey) { if (this.state.lastChecked == -1) { this.setState({ lastChecked: index }) this._filterUpdated(index) } else { let startIndex = index let endIndex = this.state.lastChecked let range = this.getLessNumber(startIndex, endIndex) let rangeArray = [] for (let i = range.less; i <= range.greater; i++) { rangeArray.push(i) } rangeArray.filter(item => { this._filterUpdated(item) }) } } else { this.setState({ lastChecked: index }) this._filterUpdated(index) } } /** * _filterUpdated method called when a filter list item is clicked * @param {Number} index Index of the filter clicked */ _filterUpdated = (index) => { const allFilters = this.props.filterList; if (!isUndefined(allFilters[index])) { const newFilterState = !allFilters[index]['selected']; this._filterData(allFilters[index]['key'], !newFilterState); } } /** * [=_selectAllClicked method called when a select all item is clicked */ _selectAllClicked = () => { const selectAllState = this.props.selectAllFilters; const newSelectAllState = !selectAllState; const searchState = this.state.searchEnabled; // const searchValue = this.searchValue; if (searchState) { return; } const visibleFiltersValues = this.props.filterList.filter((filterItem) => { if (newSelectAllState) { return (filterItem.visible && !filterItem.selected); } else { return (filterItem.visible && filterItem.selected); } }).map((filterItem) => { return filterItem.key; }); this._resetData(visibleFiltersValues, newSelectAllState); } /** * _filterData Method calls parent props filter mehtod when filters are changed * @param {String} filterValue Filter value * @param {Boolean} addFilter Add/Remove */ _filterData = (filterValue = undefined, addFilter = true) => { this.props.filterRows(filterValue, this.props.filterkey, addFilter, this.props.itemDisplayValueFunc); } /** * _resetData Method calls parent props reset mehtod * @param {Array} filterValues Array of filter values * @param {Boolean} selectAll Add/Remove */ _resetData = (filterValues = [], selectAll = true) => { this.props.resetRows(filterValues, this.props.filterkey, selectAll, this.props.itemDisplayValueFunc); } /** * _sortClicked description */ _sortClicked = () => { const currentSortType = this.props.sortType; let newSortType; if (isUndefined(currentSortType) || currentSortType === DSC_VALUE) { newSortType = ASC_VALUE; } else { newSortType = DSC_VALUE; } this.props.sortRows(newSortType, { itemSortValueFunc: this.props.itemSortValueFunc, caseSensitive: (this.props.casesensitive === 'true') ? true : false, key: this.props.filterkey, }); } /** * _searchChanged Method called when search is triggered * @param {String} searchValue [Search value] */ _searchChanged = (searchValue) => { const propKey = this.props.filterkey; this.searchValue = searchValue; const prevAppliedFilters = this.appliedSearchFilters; if (!isUndefined(searchValue, true)) { this.setState({ searchEnabled: true, }); searchValue = searchValue.toLowerCase(); const filterList = this.props.filterList; const filtersToApply = filterList.filter((filterItem) => { const filterKey = filterItem.key.toString().toLowerCase(); if (filterKey.indexOf(searchValue) < 0 && filterItem.visible) { return true; } return false; }).map((filterItem) => { return { key: propKey, value: filterItem.key, }; }); this.appliedSearchFilters = filtersToApply; // this.props.filterMultipleRows(filtersToApply, prevAppliedFilters, this.props.itemDisplayValueFunc); } else { this.setState({ searchEnabled: false, }); this.appliedSearchFilters = []; // this.props.filterMultipleRows([], prevAppliedFilters, this.props.itemDisplayValueFunc); } } /** * render * @return {JSX} */ render() { const filterState = this.state.showFilter; const showSearch = this.props.showsearch === 'false' ? false : true; const filterListItemHtml = []; let filterListHtml; if (this.props.filterList.length > 1) { if (filterState) { const searchBarHtml = showSearch ? <SearchBar searchChanged={this._searchChanged} /> : null; this.props.filterList.map((filterItem, index) => { if (filterItem.visible) { if (this.state.searchEnabled) { const filterKey = filterItem.key.toString().toLowerCase(); if (filterKey.indexOf(this.searchValue.toLowerCase()) >= 0) { return filterListItemHtml.push(<FilterListItem key={'item_' + index} filterClicked={this._handleSelectionRange} index={index} label={filterItem.display} selected={filterItem.selected} />); } else { return null; } } else { filterListItemHtml.push(<FilterListItem key={'item_' + index} filterClicked={this._handleSelectionRange} index={index} label={filterItem.display} selected={filterItem.selected} />); } } }); const filterListClass = [(this.props.alignleft === 'true') ? 'align-left ' : '', 'filter-list'].join(''); filterListHtml = (<div className={filterListClass}> {searchBarHtml} <SortIcon sort={this._sortClicked} sortType={this.props.sortType} /> <SelectAllItem filterClicked={this._selectAllClicked} selected={this.props.selectAllFilters} /> {filterListItemHtml} </div>); } const filterActive = !this.props.selectAllFilters || filterState; return (<div className="table-filter-parent" ref={(node) => { this.filterIconNode = node; }}> <FilterIcon iconClicked={this._filterIconClicked} selected={filterActive} /> {filterListHtml} </div>); } else { return (<div style={{ display: 'none' }}></div>); } } } FilterList.propTypes = { filterRows: PropTypes.func.isRequired, resetRows: PropTypes.func.isRequired, sortRows: PropTypes.func.isRequired, sortType: PropTypes.string, filterkey: PropTypes.string.isRequired, itemDisplayValueFunc: PropTypes.func, itemSortValueFunc: PropTypes.func, casesensitive: PropTypes.string, filterMultipleRows: PropTypes.func.isRequired, showsearch: PropTypes.string, alignleft: PropTypes.string, filterList: PropTypes.array, selectAllFilters: PropTypes.bool, }; export default FilterList;